Annotation of src/usr.bin/cvs/child.c, Revision 1.1
1.1 ! jfb 1: /* $OpenBSD$ */
! 2: /*
! 3: * Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
! 4: * All rights reserved.
! 5: *
! 6: * Redistribution and use in source and binary forms, with or without
! 7: * modification, are permitted provided that the following conditions
! 8: * are met:
! 9: *
! 10: * 1. Redistributions of source code must retain the above copyright
! 11: * notice, this list of conditions and the following disclaimer.
! 12: * 2. The name of the author may not be used to endorse or promote products
! 13: * derived from this software without specific prior written permission.
! 14: *
! 15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
! 16: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
! 17: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
! 18: * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
! 19: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
! 20: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
! 21: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
! 22: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
! 23: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
! 24: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 25: */
! 26: /*
! 27: * cvsd-child
! 28: * ----------
! 29: *
! 30: * This is the process taking care of cvs(1) repository requests
! 31: * This program is not meant to be run standalone and should only be started
! 32: * by the cvsd(8) process.
! 33: *
! 34: */
! 35:
! 36: #include <sys/param.h>
! 37: #include <sys/stat.h>
! 38: #include <sys/wait.h>
! 39: #include <sys/uio.h>
! 40:
! 41: #include <err.h>
! 42: #include <pwd.h>
! 43: #include <grp.h>
! 44: #include <poll.h>
! 45: #include <fcntl.h>
! 46: #include <dirent.h>
! 47: #include <stdlib.h>
! 48: #include <stdio.h>
! 49: #include <unistd.h>
! 50: #include <signal.h>
! 51: #include <errno.h>
! 52: #include <string.h>
! 53: #include <sysexits.h>
! 54:
! 55: #include "log.h"
! 56: #include "cvs.h"
! 57: #include "cvsd.h"
! 58: #include "cvspr.h"
! 59:
! 60:
! 61:
! 62: extern char *__progname;
! 63:
! 64:
! 65: int cvsd_fg = 0;
! 66:
! 67: volatile sig_atomic_t cvsd_running = 1;
! 68:
! 69: static int cvsd_privfd = -1;
! 70: static char cvsd_root[MAXPATHLEN];
! 71: static char *cvsd_motd;
! 72: static uid_t cvsd_uid = -1;
! 73: static gid_t cvsd_gid = -1;
! 74:
! 75:
! 76: /* session info */
! 77: static uid_t cvsd_sess_ruid = 0; /* UID of the cvs issuing requests */
! 78: static gid_t cvsd_sess_rgid = 0; /* UID of the cvs issuing requests */
! 79: static int cvsd_sess_fd = -1;
! 80:
! 81:
! 82: void usage (void);
! 83: void cvsd_sighdlr (int);
! 84: int cvsd_child_getreq (struct cvsd_req *);
! 85:
! 86:
! 87: /*
! 88: * cvsd_sighdlr()
! 89: *
! 90: * Generic signal handler.
! 91: */
! 92: void
! 93: cvsd_sighdlr(int signo)
! 94: {
! 95: switch (signo) {
! 96: case SIGINT:
! 97: case SIGTERM:
! 98: case SIGQUIT:
! 99: cvsd_running = 0;
! 100: break;
! 101: }
! 102: }
! 103:
! 104:
! 105: /*
! 106: * usage()
! 107: *
! 108: * Display program usage.
! 109: */
! 110: void
! 111: usage(void)
! 112: {
! 113: fprintf(stderr,
! 114: "Usage: %s [-dfhv] [-g group] "
! 115: "[-u user]\n"
! 116: "\t-d\t\tStart the server in debugging mode (very verbose)\n"
! 117: "\t-u user\t\tUse user <user> for privilege revocation\n"
! 118: "\t-v\t\tBe verbose\n",
! 119: __progname);
! 120: }
! 121:
! 122:
! 123: int
! 124: main(int argc, char **argv)
! 125: {
! 126: int ret;
! 127: struct cvsd_req req;
! 128:
! 129: if (cvs_log_init(LD_STD|LD_SYSLOG, LF_PID) < 0)
! 130: err(1, "failed to initialize logging mechanism");
! 131:
! 132: cvsd_sess_fd = CVSD_CHILD_SOCKFD;
! 133: if (getpeereid(cvsd_sess_fd, &cvsd_sess_ruid, &cvsd_sess_rgid) == -1) {
! 134: cvs_log(LP_ERRNO, "failed to get remote credentials");
! 135: exit(EX_OSERR);
! 136: }
! 137:
! 138: while ((ret = getopt(argc, argv, "dfg:hr:u:v")) != -1) {
! 139: switch (ret) {
! 140: case 'd':
! 141: cvs_log_filter(LP_FILTER_UNSET, LP_DEBUG);
! 142: cvs_log_filter(LP_FILTER_UNSET, LP_INFO);
! 143: break;
! 144: case 'f':
! 145: cvsd_fg = 1;
! 146: break;
! 147: case 'g':
! 148: cvsd_gid = atoi(optarg);
! 149: break;
! 150: case 'h':
! 151: usage();
! 152: exit(0);
! 153: /* NOTREACHED */
! 154: break;
! 155: case 'r':
! 156: strlcpy(cvsd_root, optarg, sizeof(cvsd_root));
! 157: break;
! 158: case 'u':
! 159: cvsd_uid = atoi(optarg);
! 160: break;
! 161: case 'v':
! 162: cvs_log_filter(LP_FILTER_UNSET, LP_INFO);
! 163: break;
! 164: default:
! 165: usage();
! 166: exit(EX_USAGE);
! 167: }
! 168: }
! 169:
! 170: argc -= optind;
! 171: argv += optind;
! 172: if (argc > 0)
! 173: errx(EX_USAGE, "unrecognized trailing arguments");
! 174:
! 175: /* Before getting any further, chroot to the CVS repository's root
! 176: * directory and drop all privileges to the appropriate user and
! 177: * group so we can't cause damage outside of the CVS data.
! 178: */
! 179: if (chroot(cvsd_root) == -1) {
! 180: cvs_log(LP_ERRNO, "failed to chroot to %s", cvsd_root);
! 181: exit(EX_OSERR);
! 182: }
! 183: (void)chdir("/");
! 184: cvs_log(LP_INFO, "dropping privileges to %d:%d", cvsd_uid, cvsd_gid);
! 185: if (setgid(cvsd_gid) == -1) {
! 186: cvs_log(LP_ERRNO, "failed to drop group privileges to %s",
! 187: CVSD_GROUP);
! 188: return (-1);
! 189: }
! 190:
! 191: if (setuid(cvsd_uid) == -1) {
! 192: cvs_log(LP_ERRNO, "failed to drop user privileges to %s",
! 193: CVSD_USER);
! 194: return (-1);
! 195: }
! 196:
! 197: signal(SIGINT, cvsd_sighdlr);
! 198: signal(SIGQUIT, cvsd_sighdlr);
! 199: signal(SIGTERM, cvsd_sighdlr);
! 200: signal(SIGPIPE, SIG_IGN);
! 201:
! 202: setproctitle("%s [child %d]", __progname, getpid());
! 203:
! 204: for (;;) {
! 205: ret = cvsd_child_getreq(&req);
! 206: if (ret <= 0)
! 207: break;
! 208:
! 209: switch (req.cr_op) {
! 210: case CVS_OP_DIFF:
! 211: case CVS_OP_UPDATE:
! 212: default:
! 213: }
! 214: printf("request ID: %d, nfiles = %d\n", req.cr_op,
! 215: req.cr_nfiles);
! 216: }
! 217:
! 218: close(cvsd_sess_fd);
! 219:
! 220: cvs_log_cleanup();
! 221:
! 222: return (0);
! 223: }
! 224:
! 225:
! 226: /*
! 227: * cvsd_child_getreq()
! 228: *
! 229: * Read the next request available on the session socket.
! 230: * Returns 1 if a request was received, 0 if there are no more requests to
! 231: * serve, and -1 in case of failure.
! 232: */
! 233: int
! 234: cvsd_child_getreq(struct cvsd_req *reqp)
! 235: {
! 236: ssize_t ret;
! 237: if ((ret = read(cvsd_sess_fd, reqp, sizeof(*reqp))) == -1) {
! 238: cvs_log(LP_ERRNO, "failed to read request");
! 239: } else if (ret > 0) {
! 240: printf("reqlen = %d\n", ret);
! 241: ret = 1;
! 242: }
! 243:
! 244: return ((int)ret);
! 245: }
! 246:
! 247:
! 248: /*
! 249: * cvsd_child_reqhdlr()
! 250: *
! 251: */
! 252: int
! 253: cvsd_child_reqhdlr(struct cvsp_req *req)
! 254: {
! 255: int ret;
! 256:
! 257: switch (req->req_code) {
! 258: case CVSP_REQ_MOTD:
! 259: ret = cvs_proto_sendresp(cvsd_sess_fd, CVSP_RESP_DONE,
! 260: cvsd_motd, strlen(cvsd_motd) + 1);
! 261: break;
! 262: case CVSP_REQ_VERSION:
! 263: case CVSP_REQ_GETMSG:
! 264: case CVSP_REQ_SETMSG:
! 265: default:
! 266: ret = cvs_proto_sendresp(cvsd_sess_fd, CVSP_RESP_INVREQ,
! 267: req->req_seq, NULL, 0);
! 268: }
! 269:
! 270: return (ret);
! 271: }