1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 /* 30 * UNIX shell 31 */ 32 33 #include "defs.h" 34 #include "sym.h" 35 #include "timeout.h" 36 #include <stdio.h> 37 #include <sys/types.h> 38 #include <sys/stat.h> 39 #include <sys/wait.h> 40 #include "dup.h" 41 42 #ifdef RES 43 #include <sgtty.h> 44 #endif 45 46 pid_t mypid, mypgid, mysid; 47 48 static BOOL beenhere = FALSE; 49 unsigned char tmpout[TMPOUTSZ]; 50 struct fileblk stdfile; 51 struct fileblk *standin = &stdfile; 52 int mailchk = 0; 53 54 static unsigned char *mailp; 55 static long *mod_time = 0; 56 static BOOL login_shell = FALSE; 57 58 #if vax 59 char **execargs = (char **)(0x7ffffffc); 60 #endif 61 62 #if pdp11 63 char **execargs = (char **)(-2); 64 #endif 65 66 67 static void exfile(); 68 extern unsigned char *simple(); 69 static void Ldup(int, int); 70 void settmp(void); 71 void chkmail(void); 72 void setmail(unsigned char *); 73 74 int 75 main(int c, char *v[], char *e[]) 76 { 77 int rflag = ttyflg; 78 int rsflag = 1; /* local restricted flag */ 79 unsigned char *flagc = flagadr; 80 struct namnod *n; 81 82 mypid = getpid(); 83 mypgid = getpgid(mypid); 84 mysid = getsid(mypid); 85 86 /* 87 * Do locale processing only if /usr is mounted. 88 */ 89 localedir_exists = (access(localedir, F_OK) == 0); 90 91 /* 92 * initialize storage allocation 93 */ 94 95 if (stakbot == 0) { 96 addblok((unsigned)0); 97 } 98 99 /* 100 * If the first character of the last path element of v[0] is "-" 101 * (ex. -sh, or /bin/-sh), this is a login shell 102 */ 103 if (*simple(v[0]) == '-') { 104 signal(SIGXCPU, SIG_DFL); 105 signal(SIGXFSZ, SIG_DFL); 106 107 /* 108 * As the previous comment states, this is a login shell. 109 * Therefore, we set the login_shell flag to explicitly 110 * indicate this condition. 111 */ 112 login_shell = TRUE; 113 } 114 115 stdsigs(); 116 117 /* 118 * set names from userenv 119 */ 120 121 setup_env(); 122 123 /* 124 * LC_MESSAGES is set here so that early error messages will 125 * come out in the right style. 126 * Note that LC_CTYPE is done later on and is *not* 127 * taken from the previous environ 128 */ 129 130 /* 131 * Do locale processing only if /usr is mounted. 132 */ 133 if (localedir_exists) 134 (void) setlocale(LC_ALL, ""); 135 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 136 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 137 #endif 138 (void) textdomain(TEXT_DOMAIN); 139 140 /* 141 * 'rsflag' is zero if SHELL variable is 142 * set in environment and 143 * the simple file part of the value. 144 * is rsh 145 */ 146 if (n = findnam("SHELL")) { 147 if (eq("rsh", simple(n->namval))) 148 rsflag = 0; 149 } 150 151 /* 152 * a shell is also restricted if the simple name of argv(0) is 153 * rsh or -rsh in its simple name 154 */ 155 156 #ifndef RES 157 158 if (c > 0 && (eq("rsh", simple(*v)) || eq("-rsh", simple(*v)))) 159 rflag = 0; 160 161 #endif 162 163 if (eq("jsh", simple(*v)) || eq("-jsh", simple(*v))) 164 flags |= monitorflg; 165 166 hcreate(); 167 set_dotpath(); 168 169 170 /* 171 * look for options 172 * dolc is $# 173 */ 174 dolc = options(c, v); 175 176 if (dolc < 2) { 177 flags |= stdflg; 178 { 179 180 while (*flagc) 181 flagc++; 182 *flagc++ = STDFLG; 183 *flagc = 0; 184 } 185 } 186 if ((flags & stdflg) == 0) 187 dolc--; 188 189 if ((flags & privflg) == 0) { 190 uid_t euid; 191 gid_t egid; 192 uid_t ruid; 193 gid_t rgid; 194 195 /* 196 * Determine all of the user's id #'s for this process and 197 * then decide if this shell is being entered as a result 198 * of a fork/exec. 199 * If the effective uid/gid do NOT match and the euid/egid 200 * is < 100 and the egid is NOT 1, reset the uid and gid to 201 * the user originally calling this process. 202 */ 203 euid = geteuid(); 204 ruid = getuid(); 205 egid = getegid(); 206 rgid = getgid(); 207 if ((euid != ruid) && (euid < 100)) 208 setuid(ruid); /* reset the uid to the orig user */ 209 if ((egid != rgid) && ((egid < 100) && (egid != 1))) 210 setgid(rgid); /* reset the gid to the orig user */ 211 } 212 213 dolv = (unsigned char **)v + c - dolc; 214 dolc--; 215 216 /* 217 * return here for shell file execution 218 * but not for parenthesis subshells 219 */ 220 if (setjmp(subshell)) { 221 freejobs(); 222 flags |= subsh; 223 } 224 225 /* 226 * number of positional parameters 227 */ 228 replace(&cmdadr, dolv[0]); /* cmdadr is $0 */ 229 230 /* 231 * set pidname '$$' 232 */ 233 assnum(&pidadr, (long)mypid); 234 235 /* 236 * set up temp file names 237 */ 238 settmp(); 239 240 /* 241 * default internal field separators 242 * Do not allow importing of IFS from parent shell. 243 * setup_env() may have set anything from parent shell to IFS. 244 * Always set the default ifs to IFS. 245 */ 246 assign(&ifsnod, (unsigned char *)sptbnl); 247 248 dfault(&mchknod, MAILCHECK); 249 mailchk = stoi(mchknod.namval); 250 251 /* initialize OPTIND for getopt */ 252 253 n = lookup("OPTIND"); 254 assign(n, (unsigned char *)"1"); 255 /* 256 * make sure that option parsing starts 257 * at first character 258 */ 259 _sp = 1; 260 261 if ((beenhere++) == FALSE) /* ? profile */ 262 { 263 if ((login_shell == TRUE) && (flags & privflg) == 0) { 264 265 /* system profile */ 266 267 #ifndef RES 268 269 if ((input = pathopen(nullstr, sysprofile)) >= 0) 270 exfile(rflag); /* file exists */ 271 272 #endif 273 /* user profile */ 274 275 if ((input = pathopen(homenod.namval, profile)) >= 0) { 276 exfile(rflag); 277 flags &= ~ttyflg; 278 } 279 } 280 if (rsflag == 0 || rflag == 0) { 281 if ((flags & rshflg) == 0) { 282 while (*flagc) 283 flagc++; 284 *flagc++ = 'r'; 285 *flagc = '\0'; 286 } 287 flags |= rshflg; 288 } 289 290 /* 291 * open input file if specified 292 */ 293 if (comdiv) { 294 estabf(comdiv); 295 input = -1; 296 } 297 else 298 { 299 if (flags & stdflg) { 300 input = 0; 301 } else { 302 /* 303 * If the command file specified by 'cmdadr' 304 * doesn't exist, chkopen() will fail calling 305 * exitsh(). If this is a login shell and 306 * the $HOME/.profile file does not exist, the 307 * above statement "flags &= ~ttyflg" does not 308 * get executed and this makes exitsh() call 309 * longjmp() instead of exiting. longjmp() will 310 * return to the location specified by the last 311 * active jmpbuffer, which is the one set up in 312 * the function exfile() called after the system 313 * profile file is executed (see lines above). 314 * This would cause an infinite loop, because 315 * chkopen() will continue to fail and exitsh() 316 * to call longjmp(). To make exitsh() exit instead 317 * of calling longjmp(), we then set the flag forcexit 318 * at this stage. 319 */ 320 321 flags |= forcexit; 322 input = chkopen(cmdadr, 0); 323 flags &= ~forcexit; 324 } 325 326 #ifdef ACCT 327 if (input != 0) 328 preacct(cmdadr); 329 #endif 330 comdiv--; 331 } 332 } 333 #ifdef pdp11 334 else 335 *execargs = (char *)dolv; /* for `ps' cmd */ 336 #endif 337 338 339 exfile(0); 340 done(0); 341 } 342 343 static void 344 exfile(int prof) 345 { 346 time_t mailtime = 0; /* Must not be a register variable */ 347 time_t curtime = 0; 348 349 /* 350 * move input 351 */ 352 if (input > 0) { 353 Ldup(input, INIO); 354 input = INIO; 355 } 356 357 358 setmode(prof); 359 360 if (setjmp(errshell) && prof) { 361 close(input); 362 (void) endjobs(0); 363 return; 364 } 365 /* 366 * error return here 367 */ 368 369 loopcnt = peekc = peekn = 0; 370 fndef = 0; 371 nohash = 0; 372 iopend = 0; 373 374 if (input >= 0) 375 initf(input); 376 /* 377 * command loop 378 */ 379 for (;;) { 380 tdystak(0); 381 stakchk(); /* may reduce sbrk */ 382 exitset(); 383 384 if ((flags & prompt) && standin->fstak == 0 && !eof) { 385 386 if (mailp) { 387 time(&curtime); 388 389 if ((curtime - mailtime) >= mailchk) { 390 chkmail(); 391 mailtime = curtime; 392 } 393 } 394 395 /* necessary to print jobs in a timely manner */ 396 if (trapnote & TRAPSET) 397 chktrap(); 398 399 prs(ps1nod.namval); 400 401 #ifdef TIME_OUT 402 alarm(TIMEOUT); 403 #endif 404 405 } 406 407 trapnote = 0; 408 peekc = readwc(); 409 if (eof) { 410 if (endjobs(JOB_STOPPED)) 411 return; 412 eof = 0; 413 } 414 415 #ifdef TIME_OUT 416 alarm(0); 417 #endif 418 419 { 420 struct trenod *t; 421 t = cmd(NL, MTFLG); 422 if (t == NULL && flags & ttyflg) 423 freejobs(); 424 else 425 execute(t, 0, eflag); 426 } 427 428 eof |= (flags & oneflg); 429 430 } 431 } 432 433 void 434 chkpr(void) 435 { 436 if ((flags & prompt) && standin->fstak == 0) 437 prs(ps2nod.namval); 438 } 439 440 void 441 settmp(void) 442 { 443 int len; 444 serial = 0; 445 if ((len = snprintf((char *)tmpout, TMPOUTSZ, "/tmp/sh%u", mypid)) >= 446 TMPOUTSZ) { 447 /* 448 * TMPOUTSZ should be big enough, but if it isn't, 449 * we'll at least try to create tmp files with 450 * a truncated tmpfile name at tmpout. 451 */ 452 tmpout_offset = TMPOUTSZ - 1; 453 } else { 454 tmpout_offset = len; 455 } 456 } 457 458 static void 459 Ldup(int fa, int fb) 460 { 461 #ifdef RES 462 463 dup(fa | DUPFLG, fb); 464 close(fa); 465 ioctl(fb, FIOCLEX, 0); 466 467 #else 468 469 if (fa >= 0) { 470 if (fa != fb) { 471 close(fb); 472 fcntl(fa, 0, fb); /* normal dup */ 473 close(fa); 474 } 475 fcntl(fb, 2, 1); /* autoclose for fb */ 476 } 477 478 #endif 479 } 480 481 void 482 chkmail(void) 483 { 484 unsigned char *s = mailp; 485 unsigned char *save; 486 487 long *ptr = mod_time; 488 unsigned char *start; 489 BOOL flg; 490 struct stat statb; 491 492 while (*s) { 493 start = s; 494 save = 0; 495 flg = 0; 496 497 while (*s) { 498 if (*s != COLON) { 499 if (*s == '%' && save == 0) 500 save = s; 501 502 s++; 503 } else { 504 flg = 1; 505 *s = 0; 506 } 507 } 508 509 if (save) 510 *save = 0; 511 512 if (*start && stat((const char *)start, &statb) >= 0) { 513 if (statb.st_size && *ptr && 514 statb.st_mtime != *ptr) { 515 if (save) { 516 prs(save+1); 517 newline(); 518 } 519 else 520 prs(_gettext(mailmsg)); 521 } 522 *ptr = statb.st_mtime; 523 } else if (*ptr == 0) 524 *ptr = 1; 525 526 if (save) 527 *save = '%'; 528 529 if (flg) 530 *s++ = COLON; 531 532 ptr++; 533 } 534 } 535 536 void 537 setmail(unsigned char *mailpath) 538 { 539 unsigned char *s = mailpath; 540 int cnt = 1; 541 542 long *ptr; 543 544 free(mod_time); 545 if (mailp = mailpath) { 546 while (*s) { 547 if (*s == COLON) 548 cnt += 1; 549 550 s++; 551 } 552 553 ptr = mod_time = (long *)alloc(sizeof (long) * cnt); 554 555 while (cnt) { 556 *ptr = 0; 557 ptr++; 558 cnt--; 559 } 560 } 561 } 562 563 void 564 setmode(int prof) 565 { 566 /* 567 * decide whether interactive 568 */ 569 570 if ((flags & intflg) || 571 ((flags&oneflg) == 0 && 572 isatty(output) && 573 isatty(input))) 574 575 { 576 dfault(&ps1nod, (geteuid() ? stdprompt : supprompt)); 577 dfault(&ps2nod, readmsg); 578 flags |= ttyflg | prompt; 579 if (mailpnod.namflg != N_DEFAULT) 580 setmail(mailpnod.namval); 581 else 582 setmail(mailnod.namval); 583 startjobs(); 584 } 585 else 586 { 587 flags |= prof; 588 flags &= ~prompt; 589 } 590 } 591