rexecd.c
来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 429 行
C
429 行
#ifndef lintstatic char sccsid[] = "@(#)rexecd.c 4.3 (ULTRIX) 12/6/90";#endif/************************************************************************ * * * Copyright (c) 1985, 1990 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//*----------------------------------------------------------------------- * Modification History * * 12/5/90 dlong * Numerous changes to work with enhanced security and to * remove potetnial varargs problem in error() function. * * 7/09/90 jsd * Add extern to environ declaration (for mips) * * 6/25/90 jsd * Interchange setuid() with setgid() so latter succeeds. * * 4/5/85 -- jrs * Revise to allow inetd to perform front end functions, * following the Berkeley model. * * Based on 4.2BSD labeled: * rexecd.c 4.10 83/07/02 * *----------------------------------------------------------------------- */#include <limits.h>#include <sys/ioctl.h>#include <sys/param.h>#include <sys/socket.h>#include <sys/wait.h>#include <netinet/in.h>#include <varargs.h>#include <stdio.h>#include <errno.h>#include <pwd.h>#include <signal.h>#include <netdb.h>#include <syslog.h>#include <sys/syscall.h>#include <sys/audit.h>#include <sys/svcinfo.h>#include <auth.h>#ifdef AUTHEN#include <krb.h>#endif AUTHEN#define LEN (SYSCALL_MASK_LEN+TRUSTED_MASK_LEN)extern errno;struct passwd *getpwnam();char *rindex(), *index();extern AUTHORIZATION *_auth;/* VARARGS 1 */int error();/* * remote execute server: * username\0 * password\0 * command\0 * data */struct svcinfo *svcp;static struct sockaddr_in *remhost = 0;static struct passwd *pwd=0;static AUTHORIZATION *auth=0;static char user[17];/* * Function to generate an audit record with all available, relevant * information. Called by error() for all error cases. Called by doit() for * successful case. */static int auditit(message, result)char *message;int result;{ char tmask[AUD_NPARAM+1]; char *ar[AUD_NPARAM+1]; int i=0; tmask[i] = T_LOGIN; if(pwd) ar[i++] = pwd->pw_name; else ar[i++] = user; tmask[i] = T_SERVICE; ar[i++] = "rexecd"; if(pwd) { tmask[i] = T_HOMEDIR; ar[i++] = pwd->pw_dir; tmask[i] = T_SHELL; ar[i++] = pwd->pw_shell; } if(message) { tmask[i] = T_CHARP; ar[i++] = message; } if(remhost) { tmask[i] = T_HOSTADDR2; ar[i++] = (char *) remhost->sin_addr; } if(result) tmask[i] = T_ERROR; else tmask[i] = T_RESULT; ar[i++] = (char *) result; tmask[i] = '\0'; return audgen(LOGIN, tmask, ar);}main(argc, argv) int argc; char **argv;{ int fromlen, i; struct sockaddr_in from;/* Turn off all auditing except for LOGIN and setgroups.*/ { char buf[LEN]; if ( audcntl ( SET_PROC_ACNTL, (char *)0, 0, AUDIT_AND, 0 ) == -1 ) perror ( "audcntl" ); A_PROCMASK_SET ( buf, SYS_setgroups, 1, 1 ); A_PROCMASK_SET ( buf, LOGIN, 1, 1 ); if ( audcntl ( SET_PROC_AMASK, buf, LEN, 0, 0 ) == -1 ) perror ( "audcntl" ); } fromlen = sizeof(from); if (getpeername(0, &from, &fromlen) < 0) { openlog(argv[0], LOG_PID); syslog(LOG_ERR, "getpeername: %m"); closelog(); exit(1); }/* * Fire up kerberos */#ifdef AUTHEN if((svcp = getsvc()) == NULL) fputs("Cannot access security type\n", stderr); if(svcp->svcauth.seclevel >= SEC_UPGRADE) for (i = 0 ; svcp->svcpath[SVC_AUTH][i] != SVC_LAST; i++) if (svcp->svcpath[SVC_AUTH][i] == SVC_BIND) { char *ptr, namebuf[ANAME_SZ]; if(gethostname(namebuf, sizeof(namebuf)) == -1) fputs("gethostname failure\n", stderr); if((ptr = index(namebuf, '.')) != (char *)0) *ptr = '\0'; if(krb_svc_init("hesiod", namebuf, (char *)NULL, 0, (char *)NULL, "/var/dss/kerberos/tkt/tkt.rexecd") != RET_OK) fputs("Kerberos initialization failure\n", stderr); }#endif AUTHEN (void) dup2(0, 3); (void) close(0); doit(3, &from);}char username[20] = "USER=";char homedir[64] = "HOME=";char shell[64] = "SHELL=";char *envinit[] = {homedir, shell, "PATH=:/usr/ucb:/bin:/usr/bin", username, 0};extern char **environ;struct sockaddr_in asin = { AF_INET };static char bad_login_msg[] = "Login incorrect.";doit(f, fromp) int f; struct sockaddr_in *fromp;{ char cmdbuf[NCARGS+1], *cp, *namep; char pass[PASS_MAX+1]; int s, status; u_short port; int pv[2], pid, ready, readfrom, cc; char buf[BUFSIZ], sig; int one = 1; (void) signal(SIGINT, SIG_DFL); (void) signal(SIGQUIT, SIG_DFL); (void) signal(SIGTERM, SIG_DFL);#ifdef DEBUG { int t = open("/dev/tty", 2); if (t >= 0) { ioctl(t, TIOCNOTTY, (char *)0); (void) close(t); } }#endif (void) dup2(f, 0); (void) dup2(f, 1); (void) dup2(f, 2); (void) alarm(60); port = 0; for (;;) { char c; if (read(f, &c, 1) != 1) exit(1); if (c == 0) break; port = port * 10 + c - '0'; } (void) alarm(0); if (port != 0) { s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) exit(1); if (bind(s, &asin, sizeof (asin)) < 0) exit(1); (void) alarm(60); fromp->sin_port = htons((u_short)port); if (connect(s, fromp, sizeof (*fromp)) < 0) exit(1); (void) alarm(0); } remhost = fromp; getstr(user, sizeof(user), "username"); getstr(pass, sizeof(pass), "password"); getstr(cmdbuf, sizeof(cmdbuf), "command"); (void) setpwent(); pwd = getpwnam(user); if (pwd == NULL) { sleep(1); error("Invalid account.", bad_login_msg); exit(1); } (void) endpwent(); if((status=authenticate_user(pwd, pass, "")) < 0) switch(-status) { case A_ESOFTEXP: case A_EHARDEXP: error((char *)0, "Password expired."); exit(1); break; case A_ENOLOGIN: error((char *)0, "Account disabled."); exit(1); break; default: sleep(1); error("Invalid password.", bad_login_msg); exit(1); } if(svcp->svcauth.seclevel > SEC_BSD && _auth && !(auth=getauthuid(pwd->pw_uid))) { error("Unable to get auth record.", bad_login_msg); exit(1); } if (chdir(pwd->pw_dir) < 0) { error((char *)0, "No remote directory."); exit(1); } (void) write(2, "\0", 1); if (port) { (void) pipe(pv); pid = fork(); if (pid == -1) { error((char *)0, "Try again."); exit(1); } if (pid) { (void) close(0); (void) close(1); (void) close(2); (void) close(f); (void) close(pv[1]); readfrom = (1<<s) | (1<<pv[0]); ioctl(pv[1], FIONBIO, (char *)&one); /* should set s nbio! */ do { ready = readfrom; (void) select(16, &ready, 0, 0, 0); if (ready & (1<<s)) { if (read(s, &sig, 1) <= 0) readfrom &= ~(1<<s); else (void) killpg(pid, sig); } if (ready & (1<<pv[0])) { cc = read(pv[0], buf, sizeof (buf)); if (cc <= 0) { (void) shutdown(s, 1+1); readfrom &= ~(1<<pv[0]); } else (void) write(s, buf, cc); } } while (readfrom); exit(0); } (void) setpgrp(0, getpid()); (void) close(s); (void)close(pv[0]); (void) dup2(pv[1], 2); } if (*pwd->pw_shell == '\0') pwd->pw_shell = "/bin/sh"; (void) close(f); initgroups(pwd->pw_name, pwd->pw_gid); /* do setgid before setuid, else we lose our root-uid process */ if (setgid(pwd->pw_gid) < 0) { openlog("rexecd", LOG_PID); syslog(LOG_ERR, "setgid: %m"); closelog(); exit(1); } if(auth) { if(audcntl(SET_PROC_ACNTL, (char *) 0, 0, auth->a_audit_control, 0) < 0) { openlog("rexecd", LOG_PID); syslog(LOG_ERR, "audcntl error."); exit(1); } if(audcntl(SET_PROC_AMASK, auth->a_audit_mask, SYSCALL_MASK_LEN+TRUSTED_MASK_LEN, 0) < 0) { openlog("rexecd", LOG_PID); syslog(LOG_ERR, "audit mask error."); exit(1); } if(audcntl(SETPAID, (char *) 0, 0, 0, auth->a_audit_id) < 0) { openlog("rexecd", LOG_PID); syslog(LOG_ERR, "error setting audit ID."); exit(1); } } else { audcntl(SET_PROC_ACNTL, (char *)0, 0, AUDIT_OR, 0); A_PROCMASK_SET(buf, SYS_setgroups, 0, 0); A_PROCMASK_SET(buf, LOGIN, 0, 0); audcntl(SET_PROC_AMASK, buf, LEN, 0, 0); } auditit("rexec succeeded", 0); if (setuid(pwd->pw_uid) < 0) { openlog("rexecd", LOG_PID); syslog(LOG_ERR, "setuid: %m"); closelog(); exit(1); } environ = envinit; (void) strncat(homedir, pwd->pw_dir, sizeof(homedir)-6); (void) strncat(shell, pwd->pw_shell, sizeof(shell)-7); (void) strncat(username, pwd->pw_name, sizeof(username)-6); cp = rindex(pwd->pw_shell, '/'); if (cp) cp++; else cp = pwd->pw_shell; execl(pwd->pw_shell, cp, "-c", cmdbuf, 0); perror(pwd->pw_shell); exit(1);}/* VARARGS 1 *//* * Function to report an error. This function will also cause an audit * record to be generated. The first argument is a message to place in * the audit record. If it is the NULL pointer the message placed in the * audit record will be the same as that printed out. The second * argument is the format for a sprintf. It may not be NULL. Any * remaining arguments are used as arguments in the call to sprintf. */error(va_alist)va_dcl{ va_list ap; char buf[BUFSIZ]; char *fmt, *audit; va_start(ap); audit = va_arg(ap, char *); fmt = va_arg(ap, char *); buf[0] = 1; (void) vsprintf(buf+1, fmt, ap); if(!audit) audit = buf+1; auditit(audit, 1); strcat(buf, "\n"); (void) write(2, buf, strlen(buf)); va_end(ap);}getstr(buf, cnt, err) char *buf; int cnt; char *err;{ char c; do { if (read(0, &c, 1) != 1) exit(1); *buf++ = c; if (cnt-- <= 0) { error((char *)0, "%s too long", err); exit(1); } } while (c != 0);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?