119304Speter/*- 219304Speter * Copyright (c) 1992, 1993, 1994 319304Speter * The Regents of the University of California. All rights reserved. 419304Speter * Copyright (c) 1992, 1993, 1994, 1995, 1996 519304Speter * Keith Bostic. All rights reserved. 619304Speter * 719304Speter * See the LICENSE file for redistribution information. 819304Speter */ 919304Speter 1019304Speter#include "config.h" 1119304Speter 1219304Speter#ifndef lint 13254225Speterstatic const char sccsid[] = "$Id: ex_init.c,v 10.33 2012/04/11 19:12:34 zy Exp $"; 1419304Speter#endif /* not lint */ 1519304Speter 16254225Speter#include <sys/types.h> 1719304Speter#include <sys/queue.h> 1819304Speter#include <sys/stat.h> 1919304Speter 2019304Speter#include <bitstring.h> 2119304Speter#include <fcntl.h> 2219304Speter#include <limits.h> 2319304Speter#include <stdio.h> 2419304Speter#include <stdlib.h> 2519304Speter#include <string.h> 2619304Speter#include <unistd.h> 2719304Speter 2819304Speter#include "../common/common.h" 2919304Speter#include "tag.h" 3019304Speter#include "pathnames.h" 3119304Speter 3219304Speterenum rc { NOEXIST, NOPERM, RCOK }; 3319304Speterstatic enum rc exrc_isok __P((SCR *, struct stat *, char *, int, int)); 3419304Speter 3519304Speterstatic int ex_run_file __P((SCR *, char *)); 3619304Speter 3719304Speter/* 3819304Speter * ex_screen_copy -- 3919304Speter * Copy ex screen. 4019304Speter * 4119304Speter * PUBLIC: int ex_screen_copy __P((SCR *, SCR *)); 4219304Speter */ 4319304Speterint 44254225Speterex_screen_copy(SCR *orig, SCR *sp) 4519304Speter{ 4619304Speter EX_PRIVATE *oexp, *nexp; 4719304Speter 4819304Speter /* Create the private ex structure. */ 4919304Speter CALLOC_RET(orig, nexp, EX_PRIVATE *, 1, sizeof(EX_PRIVATE)); 5019304Speter sp->ex_private = nexp; 5119304Speter 5219304Speter /* Initialize queues. */ 53254225Speter TAILQ_INIT(nexp->tq); 54254225Speter TAILQ_INIT(nexp->tagfq); 55254225Speter SLIST_INIT(nexp->cscq); 5619304Speter 5719304Speter if (orig == NULL) { 5819304Speter } else { 5919304Speter oexp = EXP(orig); 6019304Speter 6119304Speter if (oexp->lastbcomm != NULL && 62254225Speter (nexp->lastbcomm = v_wstrdup(sp, oexp->lastbcomm, 63254225Speter STRLEN(oexp->lastbcomm))) == NULL) { 6419304Speter msgq(sp, M_SYSERR, NULL); 6519304Speter return(1); 6619304Speter } 6719304Speter if (ex_tag_copy(orig, sp)) 6819304Speter return (1); 6919304Speter } 7019304Speter return (0); 7119304Speter} 7219304Speter 7319304Speter/* 7419304Speter * ex_screen_end -- 7519304Speter * End a vi screen. 7619304Speter * 7719304Speter * PUBLIC: int ex_screen_end __P((SCR *)); 7819304Speter */ 7919304Speterint 80254225Speterex_screen_end(SCR *sp) 8119304Speter{ 8219304Speter EX_PRIVATE *exp; 8319304Speter int rval; 8419304Speter 8519304Speter if ((exp = EXP(sp)) == NULL) 8619304Speter return (0); 8719304Speter 8819304Speter rval = 0; 8919304Speter 9019304Speter /* Close down script connections. */ 9119304Speter if (F_ISSET(sp, SC_SCRIPT) && sscr_end(sp)) 9219304Speter rval = 1; 9319304Speter 9419304Speter if (argv_free(sp)) 9519304Speter rval = 1; 9619304Speter 9719304Speter if (exp->ibp != NULL) 9819304Speter free(exp->ibp); 9919304Speter 10019304Speter if (exp->lastbcomm != NULL) 10119304Speter free(exp->lastbcomm); 10219304Speter 103254225Speter if (exp->ibcw.bp1.c != NULL) 104254225Speter free(exp->ibcw.bp1.c); 105254225Speter 10619304Speter if (ex_tag_free(sp)) 10719304Speter rval = 1; 10819304Speter 109254225Speter if (cscope_end(sp)) 110254225Speter rval = 1; 111254225Speter 11219304Speter /* Free private memory. */ 11319304Speter free(exp); 11419304Speter sp->ex_private = NULL; 11519304Speter 11619304Speter return (rval); 11719304Speter} 11819304Speter 11919304Speter/* 12019304Speter * ex_optchange -- 12119304Speter * Handle change of options for ex. 12219304Speter * 12319304Speter * PUBLIC: int ex_optchange __P((SCR *, int, char *, u_long *)); 12419304Speter */ 12519304Speterint 126254225Speterex_optchange(SCR *sp, int offset, char *str, u_long *valp) 12719304Speter{ 12819304Speter switch (offset) { 12919304Speter case O_TAGS: 13019304Speter return (ex_tagf_alloc(sp, str)); 13119304Speter } 13219304Speter return (0); 13319304Speter} 13419304Speter 13519304Speter/* 13619304Speter * ex_exrc -- 13719304Speter * Read the EXINIT environment variable and the startup exrc files, 13819304Speter * and execute their commands. 13919304Speter * 14019304Speter * PUBLIC: int ex_exrc __P((SCR *)); 14119304Speter */ 14219304Speterint 143254225Speterex_exrc(SCR *sp) 14419304Speter{ 14519304Speter struct stat hsb, lsb; 146254225Speter char *p, *path; 147254225Speter CHAR_T *wp; 148254225Speter size_t wlen; 14919304Speter 15019304Speter /* 15119304Speter * Source the system, environment, $HOME and local .exrc values. 15219304Speter * Vi historically didn't check $HOME/.exrc if the environment 15319304Speter * variable EXINIT was set. This is all done before the file is 15419304Speter * read in, because things in the .exrc information can set, for 15519304Speter * example, the recovery directory. 15619304Speter * 15719304Speter * !!! 15819304Speter * While nvi can handle any of the options settings of historic vi, 15919304Speter * the converse is not true. Since users are going to have to have 16019304Speter * files and environmental variables that work with both, we use nvi 16119304Speter * versions of both the $HOME and local startup files if they exist, 16219304Speter * otherwise the historic ones. 16319304Speter * 16419304Speter * !!! 16519304Speter * For a discussion of permissions and when what .exrc files are 16619304Speter * read, see the comment above the exrc_isok() function below. 16719304Speter * 16819304Speter * !!! 16919304Speter * If the user started the historic of vi in $HOME, vi read the user's 17019304Speter * .exrc file twice, as $HOME/.exrc and as ./.exrc. We avoid this, as 17119304Speter * it's going to make some commands behave oddly, and I can't imagine 17219304Speter * anyone depending on it. 17319304Speter */ 17419304Speter switch (exrc_isok(sp, &hsb, _PATH_SYSEXRC, 1, 0)) { 17519304Speter case NOEXIST: 17619304Speter case NOPERM: 17719304Speter break; 17819304Speter case RCOK: 17919304Speter if (ex_run_file(sp, _PATH_SYSEXRC)) 18019304Speter return (1); 18119304Speter break; 18219304Speter } 18319304Speter 18419304Speter /* Run the commands. */ 18519304Speter if (EXCMD_RUNNING(sp->gp)) 18619304Speter (void)ex_cmd(sp); 18719304Speter if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE)) 18819304Speter return (0); 18919304Speter 19019304Speter if ((p = getenv("NEXINIT")) != NULL) { 191254225Speter CHAR2INT(sp, p, strlen(p) + 1, wp, wlen); 192254225Speter if (ex_run_str(sp, "NEXINIT", wp, wlen - 1, 1, 0)) 19319304Speter return (1); 19419304Speter } else if ((p = getenv("EXINIT")) != NULL) { 195254225Speter CHAR2INT(sp, p, strlen(p) + 1, wp, wlen); 196254225Speter if (ex_run_str(sp, "EXINIT", wp, wlen - 1, 1, 0)) 19719304Speter return (1); 19819304Speter } else if ((p = getenv("HOME")) != NULL && *p) { 199254225Speter int st = 0; 200254225Speter 201254225Speter if ((path = join(p, _PATH_NEXRC)) == NULL) { 202254225Speter msgq(sp, M_SYSERR, NULL); 203254225Speter return (1); 204254225Speter } 20519304Speter switch (exrc_isok(sp, &hsb, path, 0, 1)) { 20619304Speter case NOEXIST: 207254225Speter free(path); 208254225Speter if ((path = join(p, _PATH_EXRC)) == NULL) { 209254225Speter msgq(sp, M_SYSERR, NULL); 210254225Speter return (1); 211254225Speter } 21219304Speter if (exrc_isok(sp, 21319304Speter &hsb, path, 0, 1) == RCOK && ex_run_file(sp, path)) 214254225Speter st = 1; 21519304Speter break; 21619304Speter case NOPERM: 21719304Speter break; 21819304Speter case RCOK: 21919304Speter if (ex_run_file(sp, path)) 220254225Speter st = 1; 22119304Speter break; 22219304Speter } 223254225Speter free(path); 224254225Speter if (st) 225254225Speter return st; 22619304Speter } 22719304Speter 22819304Speter /* Run the commands. */ 22919304Speter if (EXCMD_RUNNING(sp->gp)) 23019304Speter (void)ex_cmd(sp); 23119304Speter if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE)) 23219304Speter return (0); 23319304Speter 23419304Speter /* Previous commands may have set the exrc option. */ 23519304Speter if (O_ISSET(sp, O_EXRC)) { 23619304Speter switch (exrc_isok(sp, &lsb, _PATH_NEXRC, 0, 0)) { 23719304Speter case NOEXIST: 23819304Speter if (exrc_isok(sp, &lsb, _PATH_EXRC, 0, 0) == RCOK && 23919304Speter (lsb.st_dev != hsb.st_dev || 24019304Speter lsb.st_ino != hsb.st_ino) && 24119304Speter ex_run_file(sp, _PATH_EXRC)) 24219304Speter return (1); 24319304Speter break; 24419304Speter case NOPERM: 24519304Speter break; 24619304Speter case RCOK: 24719304Speter if ((lsb.st_dev != hsb.st_dev || 24819304Speter lsb.st_ino != hsb.st_ino) && 24919304Speter ex_run_file(sp, _PATH_NEXRC)) 25019304Speter return (1); 25119304Speter break; 25219304Speter } 25319304Speter /* Run the commands. */ 25419304Speter if (EXCMD_RUNNING(sp->gp)) 25519304Speter (void)ex_cmd(sp); 25619304Speter if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE)) 25719304Speter return (0); 25819304Speter } 25919304Speter 26019304Speter return (0); 26119304Speter} 26219304Speter 26319304Speter/* 26419304Speter * ex_run_file -- 26519304Speter * Set up a file of ex commands to run. 26619304Speter */ 26719304Speterstatic int 268254225Speterex_run_file(SCR *sp, char *name) 26919304Speter{ 27019304Speter EXCMD cmd; 271254225Speter CHAR_T *wp; 272254225Speter size_t wlen; 27319304Speter 274254225Speter ex_cinit(sp, &cmd, C_SOURCE, 0, OOBLNO, OOBLNO, 0); 275254225Speter CHAR2INT(sp, name, strlen(name)+1, wp, wlen); 276254225Speter argv_exp0(sp, &cmd, wp, wlen - 1); 27719304Speter return (ex_source(sp, &cmd)); 27819304Speter} 27919304Speter 28019304Speter/* 28119304Speter * ex_run_str -- 28219304Speter * Set up a string of ex commands to run. 28319304Speter * 284254225Speter * PUBLIC: int ex_run_str __P((SCR *, char *, CHAR_T *, size_t, int, int)); 28519304Speter */ 28619304Speterint 287254225Speterex_run_str(SCR *sp, char *name, CHAR_T *str, size_t len, int ex_flags, int nocopy) 28819304Speter{ 28919304Speter GS *gp; 29019304Speter EXCMD *ecp; 29119304Speter 29219304Speter gp = sp->gp; 29319304Speter if (EXCMD_RUNNING(gp)) { 29419304Speter CALLOC_RET(sp, ecp, EXCMD *, 1, sizeof(EXCMD)); 295254225Speter SLIST_INSERT_HEAD(gp->ecq, ecp, q); 29619304Speter } else 29719304Speter ecp = &gp->excmd; 29819304Speter 29919304Speter F_INIT(ecp, 30019304Speter ex_flags ? E_BLIGNORE | E_NOAUTO | E_NOPRDEF | E_VLITONLY : 0); 30119304Speter 30219304Speter if (nocopy) 30319304Speter ecp->cp = str; 30419304Speter else 305254225Speter if ((ecp->cp = v_wstrdup(sp, str, len)) == NULL) 30619304Speter return (1); 30719304Speter ecp->clen = len; 30819304Speter 30919304Speter if (name == NULL) 31019304Speter ecp->if_name = NULL; 31119304Speter else { 31219304Speter if ((ecp->if_name = v_strdup(sp, name, strlen(name))) == NULL) 31319304Speter return (1); 31419304Speter ecp->if_lno = 1; 31519304Speter F_SET(ecp, E_NAMEDISCARD); 31619304Speter } 31719304Speter 31819304Speter return (0); 31919304Speter} 32019304Speter 32119304Speter/* 32219304Speter * exrc_isok -- 32319304Speter * Check a .exrc file for source-ability. 32419304Speter * 32519304Speter * !!! 32619304Speter * Historically, vi read the $HOME and local .exrc files if they were owned 32719304Speter * by the user's real ID, or the "sourceany" option was set, regardless of 32819304Speter * any other considerations. We no longer support the sourceany option as 32919304Speter * it's a security problem of mammoth proportions. We require the system 33019304Speter * .exrc file to be owned by root, the $HOME .exrc file to be owned by the 33119304Speter * user's effective ID (or that the user's effective ID be root) and the 33219304Speter * local .exrc files to be owned by the user's effective ID. In all cases, 33319304Speter * the file cannot be writeable by anyone other than its owner. 33419304Speter * 33519304Speter * In O'Reilly ("Learning the VI Editor", Fifth Ed., May 1992, page 106), 33619304Speter * it notes that System V release 3.2 and later has an option "[no]exrc". 33719304Speter * The behavior is that local .exrc files are read only if the exrc option 33819304Speter * is set. The default for the exrc option was off, so, by default, local 33919304Speter * .exrc files were not read. The problem this was intended to solve was 34019304Speter * that System V permitted users to give away files, so there's no possible 34119304Speter * ownership or writeability test to ensure that the file is safe. 34219304Speter * 34319304Speter * POSIX 1003.2-1992 standardized exrc as an option. It required the exrc 34419304Speter * option to be off by default, thus local .exrc files are not to be read 34519304Speter * by default. The Rationale noted (incorrectly) that this was a change 34619304Speter * to historic practice, but correctly noted that a default of off improves 34719304Speter * system security. POSIX also required that vi check the effective user 34819304Speter * ID instead of the real user ID, which is why we've switched from historic 34919304Speter * practice. 35019304Speter * 35119304Speter * We initialize the exrc variable to off. If it's turned on by the system 35219304Speter * or $HOME .exrc files, and the local .exrc file passes the ownership and 35319304Speter * writeability tests, then we read it. This breaks historic 4BSD practice, 35419304Speter * but it gives us a measure of security on systems where users can give away 35519304Speter * files. 35619304Speter */ 35719304Speterstatic enum rc 358254225Speterexrc_isok(SCR *sp, struct stat *sbp, char *path, int rootown, int rootid) 35919304Speter{ 36019304Speter enum { ROOTOWN, OWN, WRITER } etype; 36119304Speter uid_t euid; 36219304Speter int nf1, nf2; 363254225Speter char *a, *b, *buf; 36419304Speter 36519304Speter /* Check for the file's existence. */ 36619304Speter if (stat(path, sbp)) 36719304Speter return (NOEXIST); 36819304Speter 36919304Speter /* Check ownership permissions. */ 37019304Speter euid = geteuid(); 37119304Speter if (!(rootown && sbp->st_uid == 0) && 37219304Speter !(rootid && euid == 0) && sbp->st_uid != euid) { 37319304Speter etype = rootown ? ROOTOWN : OWN; 37419304Speter goto denied; 37519304Speter } 37619304Speter 37719304Speter /* Check writeability. */ 37819304Speter if (sbp->st_mode & (S_IWGRP | S_IWOTH)) { 37919304Speter etype = WRITER; 38019304Speter goto denied; 38119304Speter } 38219304Speter return (RCOK); 38319304Speter 38419304Speterdenied: a = msg_print(sp, path, &nf1); 385254225Speter if (strchr(path, '/') == NULL && (buf = getcwd(NULL, 0)) != NULL) { 386254225Speter char *p; 387254225Speter 38819304Speter b = msg_print(sp, buf, &nf2); 389254225Speter if ((p = join(b, a)) == NULL) { 390254225Speter msgq(sp, M_SYSERR, NULL); 391254225Speter goto err; 392254225Speter } 39319304Speter switch (etype) { 39419304Speter case ROOTOWN: 39519304Speter msgq(sp, M_ERR, 396254225Speter "128|%s: not sourced: not owned by you or root", p); 39719304Speter break; 39819304Speter case OWN: 39919304Speter msgq(sp, M_ERR, 400254225Speter "129|%s: not sourced: not owned by you", p); 40119304Speter break; 40219304Speter case WRITER: 40319304Speter msgq(sp, M_ERR, 404254225Speter "130|%s: not sourced: writeable by a user other than the owner", p); 40519304Speter break; 40619304Speter } 407254225Speter free(p); 408254225Spetererr: free(buf); 40919304Speter if (nf2) 41019304Speter FREE_SPACE(sp, b, 0); 41119304Speter } else 41219304Speter switch (etype) { 41319304Speter case ROOTOWN: 41419304Speter msgq(sp, M_ERR, 41519304Speter "128|%s: not sourced: not owned by you or root", a); 41619304Speter break; 41719304Speter case OWN: 41819304Speter msgq(sp, M_ERR, 41919304Speter "129|%s: not sourced: not owned by you", a); 42019304Speter break; 42119304Speter case WRITER: 42219304Speter msgq(sp, M_ERR, 42319304Speter "130|%s: not sourced: writeable by a user other than the owner", a); 42419304Speter break; 42519304Speter } 42619304Speter 42719304Speter if (nf1) 42819304Speter FREE_SPACE(sp, a, 0); 42919304Speter return (NOPERM); 43019304Speter} 431