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