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