#include #include #include #include #include #include #include #include #include "lib.h" #define UUU "unable to " void w(char *s) { write(2, s, str_len(s)); } void e(char *x0, char *x1) { w("\nngetty-argv: "); w(x0); w(x1); w("\n"); sleep(1); } /* sleep is needed to see the erros. see the option clear also */ unsigned int expand_string(char *tmp, char *string, char *user, char *tty) { char *s=string, *pos=tmp, *exp, ch, found_one = 0; for (; (ch=*s); s++) { if (ch == '%') { found_one = 1; ch = s[1]; exp = user; switch (ch) { case 'T': exp = tty; case 'U': pos += (tmp) ? str_copy(pos, exp) : str_len(exp); ++s; break; case '%': /* %%U -> %U */ ++s; default: ch = *s; goto non_special; } } else { non_special: if (tmp) *pos = ch; ++pos; } } if (found_one) { if (tmp==0) return pos - tmp + 1; else *pos = 0; } return 0; } int main(int argc, char **argv) { char **arg=0, **ee, **aa, *in=0, *s, ch; char *user, *tty, flagsetsid=0, flagdaemon=0, flagtty=0, *flagpid=0; unsigned long n; uid_t uid=0; gid_t gid=0; if (argc<2) { usage: e("usage:\n\tngetty-argv [Options][--]ArgvString [user [tty]]\n\n", "\tArgvString:\t:/bin/sleep:hacker_sleep:39:other:args...\n" "\tOptions:\t:-D:-S:-N:-C:-u123:-g59:-a45:-s3:-d/tmp:-r/var/tmp\n" "\tOptions:\t:-e,HOME=/,TERM=linux:-p/var/run/ngetty.pid\n" "\tExample:\t:-u106:-g506:-d/var/qmail:--:./bin/qmail-qread:queue\n"); return 100; } user =(argc>2) ? argv[2] : ""; tty =(argc>3) ? argv[3] : ""; do { n = expand_string(in, argv[1], user, tty); if (n==0) break; in = alloca(n); } while (1); if (in==0) in=argv[1]; ch = *in++; /* don't use '%' as split char */ if (ch == 0 || *in == 0) goto usage; GLOBAL_split_plus(arg,in,ch, n,5); if (n < 2) goto usage; for (aa=arg; (s=*aa); aa++) { if (*s != '-') break; s += 2; n=x_atoi(s); switch (s[-1]) { case 'e': ee = 0; ch = *s++; if (ch) GLOBAL_split(ee,s,ch, n); environ = ee; break; case 'D': flagdaemon=1; break; case 'S': flagsetsid=1; break; case 'N': flagtty=1; break; case 'C': flagtty=2; break; case 'p': if (*s) flagpid=s; break; case 'g': gid = n; break; case 'u': uid = n; break; case 'a': alarm(n); break; case 's': sleep(n); break; case 'd': if (chdir(s)) { e(s, ": chdir error"); return 100; } break; case 'r': if (chroot(s)) { e(s, ": chroot error"); return 100; } break; case '-': aa++; goto do_it; default: e(s-2, " : unknown option"); return 1; } } do_it: if (flagdaemon) { int pid; while ((pid=fork()) <0) sleep(1); if (pid) _exit(0); } if (flagsetsid) setsid(); if (flagtty==1) ioctl(0, TIOCNOTTY, (void *)1); if (flagtty==2) ioctl(0, TIOCSCTTY, (void *)1); if (flagpid) { int fd = open(flagpid, O_RDWR | O_TRUNC | O_CREAT, 0644); if (fd>=0) { char tmp[3*sizeof(unsigned long)]; n=fmt_ulong(tmp, getpid()); tmp[n] = '\n'; write(fd, tmp, n+1); close(fd); } } if (uid || gid) { if (gid==0) gid = uid; if (setgroups(1,&gid) || setgid(gid) || setuid(uid)) { e(UUU, "set uidgid"); return 100; } } s = *aa++; if (s==0 || *aa==0) return 0; if (aa[0][0] == 0) aa[0] = s; execve(s, aa, environ); e(s, ": exec error"); return 127; }