/* load the history * ----------------------------------------------------------------------- */ void history_load(void) { unsigned int i; unsigned int hlen; char fname[PATH_MAX + 1]; hlen = str_copyn(fname, sh_home, PATH_MAX); if(hlen >= PATH_MAX - 3) return; /* append a trailing slash if not already there */ if(hlen && fname[hlen - 1] != '/') fname[hlen++] = '/'; fname[hlen++] = '.'; /* mapped history entries */ history_mapped = 0; for(i = 0; history_files[i]; i++) { /* append history file name */ str_copyn(&fname[hlen], history_files[i], PATH_MAX - hlen); /* then try to open the history file */ if(buffer_mmapread(&history_buffer, fname) == 0) break; } /* we tried all files: nothing to load */ if(history_files[i] == NULL) return; /* loop through the mapped history file and separate * history entries using nul-string-termination * * note that quote-balancing is applied because there * may be quoted multiline words in the history */ while(history_buffer.p < history_buffer.n) { unsigned long len; /* next entry will begin after the termination */ if(!(len = history_cmdlen(&history_buffer.x[history_buffer.p]))) break; while(parse_isspace(history_buffer.x[history_buffer.p])) history_buffer.p++; history_set(&history_buffer.x[history_buffer.p]); history_advance(); history_mapped++; history_buffer.p += len; } /* unmap the file if it didn't contain any entries */ if(history_buffer.n && history_mapped == 0) buffer_close(&history_buffer); }
static void print_escape(char *x, int wall) { char ch, *y, *start, *from = "abefnrtv\\c", *to= "\a\b\033\f\n\r\t\v\\"; unsigned long len; start = alloca(str_len(x) + 3); for (y=start; (ch=*x); x++) { if (ch == '\\') { unsigned long u; len = scan_8ulong(x+1, &u); if (len) { /* 012...9 */ ch = u; x += len; } else { len = str_chr(from, x[1]); switch (from[len]) { case 0: break; case 'c': goto do_it; default: /* \a\b... */ ++x; ch = to[len]; } } } *y++ = ch; } *y++ = '\n'; do_it: len = y-start; if (wall==0) write(1, start, len); else { struct utmp u; int fd, r; char line[8 + sizeof(u.ut_line)]; fd = open(_PATH_UTMP, O_RDONLY | O_NOCTTY); if (fd < 0) return; while (utmp_io(fd, &u, F_RDLCK)) { if (u.ut_type != USER_PROCESS) continue; if (u.ut_user[0] == 0 || u.ut_pid < 2 || u.ut_line[0] == 0 || u.ut_line[0] == '/') continue; y = line; y += str_copyn(y, "/dev/", 8); y += str_copyn(y, u.ut_line, sizeof(u.ut_line)); y[0] = 0; if (line[str_chr(line, '.')]) continue; if (kill(u.ut_pid, 0) && errno == ESRCH) continue; r = open(line, O_WRONLY | O_NOCTTY | O_NDELAY); if (r < 0) continue; write(r, start, len); close(r); } close(fd); } }
/* The 'channel_exec' function executes new process. If terminal is requsted, than users shell is executed, if exec is requested, than command 'cmd' is executed. Process is executed under appropriate users UID. */ int channel_exec(const char *cmd) { char *run[4]; char *shell; char *name; int fd[3]; char ln[32]; if (channel.maxpacket == 0) bug_proto(); if (channel.pid != 0 ) bug_proto(); if (channel.flagterminal) { channel.pid = channel_forkpty(fd, channel.master, channel.slave); if (channel.pid > 0) { name = ptsname(fd[0]); if (!name) bug(); if (!str_copyn(channel.termname, sizeof channel.termname, name)) bug_nomem(); } } else { channel.pid = channel_fork(fd); } if (channel.pid == -1) return 0; if (channel.pid == 0) { logsys_login(channel.user, channel.remoteip, 0, 0); if (!channel_droppriv(channel.user, &shell)) _exit(111); if (cmd) { run[0] = shell; run[1] = (char *)"-c"; run[2] = (char *)cmd; run[3] = 0; } else { if (!loginshell(ln, sizeof ln, shell)) bug(); run[0] = ln; run[1] = 0; } signal(SIGPIPE, SIG_DFL); newenv_exec(shell, run); _exit(111); } channel.fd0 = fd[0]; channel.fd1 = fd[1]; channel.fd2 = fd[2]; channel.len0 = 0; newenv_purge(); if (channel.flagterminal && channel.pid > 0) channel_ptyresize(channel.a, channel.b, channel.x, channel.y); return 1; }
/* The 'channel_open' function opens the channel. It sets 'localwindow' and maxpacket, values obtained from from SSH_MSG_CHANNEL_OPEN message. Function also obtaines connection information and sets environment variables PATH, SSH_CONNECTION and MAIL. */ int channel_open(const char *user, crypto_uint32 id, crypto_uint32 remotewindow, crypto_uint32 maxpacket, crypto_uint32 *localwindow) { struct buf b = { channel.buf0, 0, CHANNEL_BUFSIZE }; if (!localwindow) bug_inval(); if (!maxpacket) bug_inval(); if (!remotewindow) bug_inval(); if (channel.maxpacket != 0) bug_proto(); if (channel.pid != 0) bug_proto(); /* copy user-name */ if (!str_copyn(channel.user, sizeof channel.user, user)) bug_nomem(); /* set id, maxpacket, remotewindow, localwindow */ channel.id = id; channel.maxpacket = maxpacket; channel.remotewindow = remotewindow; channel.localwindow = *localwindow = CHANNEL_BUFSIZE; /* copy PATH */ if (!newenv_copyenv("PATH")) if (!newenv_env("PATH", "/bin:/usr/bin")) return 0; /* create env. SSH_CONNECTION */ connectioninfo(channel.localip, channel.localport, channel.remoteip, channel.remoteport); buf_purge(&b); buf_puts(&b, channel.remoteip); buf_puts(&b, " "); buf_puts(&b, channel.remoteport); buf_puts(&b, " "); buf_puts(&b, channel.localip); buf_puts(&b, " "); buf_puts(&b, channel.localport); buf_putnum8(&b, 0); if (!newenv_env("SSH_CONNECTION", (char *)b.buf)) return 0; /* create env. MAIL */ #ifdef _PATH_MAILDIR buf_purge(&b); buf_puts(&b, _PATH_MAILDIR); buf_puts(&b, "/"); buf_puts(&b, user); buf_putnum8(&b, 0); if (!newenv_env("MAIL", (char *)b.buf)) return 0; #endif purge(channel.buf0, sizeof channel.buf0); return 1; }
union node* expand_param(struct nargparam* param, union node** nptr, struct vartab* varstack, char* argv[], int exitcode, int flags) { union node* n = *nptr; stralloc value; char* str = NULL; const char *v = NULL; unsigned long argc, vlen = 0; for(argc = 0; argv[argc]; ++argc) ; stralloc_init(&value); /* treat special arguments */ if(param->flag & S_SPECIAL) { switch(param->flag & S_SPECIAL) { /* $# substitution */ case S_ARGC: { stralloc_catulong0(&value, argc, 0); break; } /* $* substitution */ case S_ARGV: { char** s; for(s = argv; *s;) { stralloc_cats(&n->narg.stra, *s); if(*++s) stralloc_catc(&n->narg.stra, ' '); } break; } /* $@ substitution */ case S_ARGVS: { unsigned int i = 0; while(i < argc) { param->flag &= ~S_SPECIAL; param->flag |= S_ARG; param->numb = 1 + i; n = expand_param(param, nptr, varstack, argv, exitcode,flags); if(++i < argc) nptr = &n->list.next; } return n; } /* $? substitution */ case S_EXITCODE: { stralloc_catulong0(&value, exitcode, 0); break; } /* $- substitution */ case S_FLAGS: break; /* $! substitution */ case S_BGEXCODE: break; /* $[0-9] arg subst */ case S_ARG: { if(param->numb == 0) { /* stralloc_cats(&value, sh_argv0); */ } else if(param->numb - 1 < argc) { stralloc_cats(&value, argv[param->numb - 1]); } break; } /* $$ arg subst */ case S_PID: { stralloc_catulong0(&value, getpid(), 0); break; } } /* special parameters are always set */ if(value.len) { stralloc_nul(&value); v = value.s; } vlen = value.len; } /* ..and variable substitutions */ else { size_t offset; /* look for the variable. if the S_NULL flag is set and we have a var which is null set v to NULL */ if((v = var_get(varstack, param->name, &offset))) { if(v[offset] == '\0' && (param->flag & S_NULL)) { v = NULL; vlen = 0; } else { v = &v[offset]; vlen = str_len(v); } } } /* check for S_STRLEN substitution */ if(param->flag & S_STRLEN) { char lstr[FMT_ULONG]; n = expand_cat(lstr, fmt_ulong(lstr, vlen), nptr, varstack, flags); stralloc_free(&value); return n; } str = str_ndup(v, vlen); /* otherwise expand the apropriate variable/word subst */ switch(param->flag & S_VAR) { /* return word if parameter unset (or null) */ case S_DEFAULT: { if(v) n = expand_cat(v, vlen, nptr, varstack, flags); /* unset, substitute */ else n = expand_arg(¶m->word->narg, nptr, varstack, argv, exitcode, flags); break; } /* if parameter unset (or null) then expand word to it and substitute paramter */ case S_ASGNDEF: { if(v) n = expand_cat(v, vlen, nptr, varstack, flags); else { n = expand_arg(¶m->word->narg, nptr, varstack, argv, exitcode, flags | X_NOSPLIT); var_setvsa(param->name, /* BUG */ &n->narg.stra, V_DEFAULT); } break; } /* indicate error if null or unset */ case S_ERRNULL: { if(v) n = expand_cat(v, vlen, nptr, varstack, flags); else { union node* tmpnode = NULL; n = expand_arg(¶m->word->narg, &tmpnode, varstack, argv, exitcode, flags); errmsg_warn((n && n->narg.stra.s) ? n->narg.stra.s : "parameter null or not set", 0); if(tmpnode) tree_free(tmpnode); } break; } /* if parameter unset (or null) then substitute null, otherwise substitute word */ case S_ALTERNAT: { if(v) n = expand_arg(¶m->word->narg, nptr, varstack, argv, exitcode, flags); break; /* remove smallest matching suffix */ case S_RSSFX: { int i; stralloc sa; if(v && vlen) { expand_copysa(param->word, &sa, varstack, argv, exitcode, 0); stralloc_nul(&sa); for(i = vlen - 1; i >= 0; i--) if(fnmatch(sa.s, str + i, FNM_PERIOD) == 0) break; n = expand_cat(v, (i < 0 ? vlen : i), nptr, varstack, flags); } break; } } /* remove largest matching suffix */ case S_RLSFX: { unsigned int i; stralloc sa; if(v && vlen) { expand_copysa(param->word, &sa, varstack, argv, exitcode, 0); stralloc_nul(&sa); for(i = 0; i <= vlen; i++) if(fnmatch(sa.s, str + i, FNM_PERIOD) == 0) break; n = expand_cat(v, (i > vlen ? vlen : i), nptr, varstack, flags); } break; } /* remove smallest matching prefix */ case S_RSPFX: { unsigned int i; stralloc sa; if(v && vlen) { expand_copysa(param->word, &sa, varstack, argv, exitcode, 0); stralloc_nul(&sa); for(i = 1; i <= vlen; i++) { str_copyn(str, v, i); if(fnmatch(sa.s, (char*)v, FNM_PERIOD) == 0) break; } if(i > vlen) i = 0; n = expand_cat(v + i, vlen - i, nptr, varstack, flags); str_copy(str, v); } break; } /* remove largest matching prefix */ case S_RLPFX: { unsigned int i; stralloc sa; if(v && vlen) { expand_copysa(param->word, &sa, varstack, argv, exitcode, 0); stralloc_nul(&sa); for(i = vlen; i > 0; i--) { str_copyn(str, v, i); if(fnmatch(sa.s, (char*)v, FNM_PERIOD) == 0) break; } if(i == 0) i = vlen; n = expand_cat(v + i, vlen - i, nptr, varstack, flags); str_copy(str, v); } break; } } free(str); stralloc_free(&value); return n; }