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