xref: /openbsd-src/usr.bin/cvs/remote.c (revision 1a0afcde32b2740b21c2faebb94e010e5d3163d8)
1*1a0afcdeSderaadt /*	$OpenBSD: remote.c,v 1.34 2021/11/28 19:28:42 deraadt Exp $	*/
29fac60a5Sjoris /*
39fac60a5Sjoris  * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
49fac60a5Sjoris  *
59fac60a5Sjoris  * Permission to use, copy, modify, and distribute this software for any
69fac60a5Sjoris  * purpose with or without fee is hereby granted, provided that the above
79fac60a5Sjoris  * copyright notice and this permission notice appear in all copies.
89fac60a5Sjoris  *
99fac60a5Sjoris  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
109fac60a5Sjoris  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
119fac60a5Sjoris  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
129fac60a5Sjoris  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
139fac60a5Sjoris  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
149fac60a5Sjoris  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
159fac60a5Sjoris  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
169fac60a5Sjoris  */
179fac60a5Sjoris 
18*1a0afcdeSderaadt #include <sys/types.h>
191f8531bdSotto #include <sys/stat.h>
201f8531bdSotto 
211f8531bdSotto #include <errno.h>
221f8531bdSotto #include <fcntl.h>
231f8531bdSotto #include <stdlib.h>
241f8531bdSotto #include <string.h>
251f8531bdSotto #include <unistd.h>
269fac60a5Sjoris 
27bb59aeccStobias #include "atomicio.h"
289fac60a5Sjoris #include "cvs.h"
299fac60a5Sjoris #include "remote.h"
309fac60a5Sjoris 
31b9fc9a72Sderaadt #define MINIMUM(a, b)	(((a) < (b)) ? (a) : (b))
32*1a0afcdeSderaadt #define _MAXBSIZE	(64 * 1024)
33b9fc9a72Sderaadt 
349fac60a5Sjoris struct cvs_resp *
cvs_remote_get_response_info(const char * response)359fac60a5Sjoris cvs_remote_get_response_info(const char *response)
369fac60a5Sjoris {
379fac60a5Sjoris 	int i;
389fac60a5Sjoris 
399fac60a5Sjoris 	for (i = 0; cvs_responses[i].supported != -1; i++) {
409fac60a5Sjoris 		if (!strcmp(cvs_responses[i].name, response))
419fac60a5Sjoris 			return (&(cvs_responses[i]));
429fac60a5Sjoris 	}
439fac60a5Sjoris 
449fac60a5Sjoris 	return (NULL);
459fac60a5Sjoris }
469fac60a5Sjoris 
479fac60a5Sjoris struct cvs_req *
cvs_remote_get_request_info(const char * request)489fac60a5Sjoris cvs_remote_get_request_info(const char *request)
499fac60a5Sjoris {
509fac60a5Sjoris 	int i;
519fac60a5Sjoris 
529fac60a5Sjoris 	for (i = 0; cvs_requests[i].supported != -1; i++) {
539fac60a5Sjoris 		if (!strcmp(cvs_requests[i].name, request))
549fac60a5Sjoris 			return (&(cvs_requests[i]));
559fac60a5Sjoris 	}
569fac60a5Sjoris 
579fac60a5Sjoris 	return (NULL);
589fac60a5Sjoris }
599fac60a5Sjoris 
609fac60a5Sjoris void
cvs_remote_output(char * data)610fcddf58Sotto cvs_remote_output(char *data)
629fac60a5Sjoris {
639fac60a5Sjoris 	FILE *out;
64bb59aeccStobias 	size_t len;
6500b139a2Stobias 	char nl = '\n';
669fac60a5Sjoris 
679fac60a5Sjoris 	if (cvs_server_active)
689fac60a5Sjoris 		out = stdout;
699fac60a5Sjoris 	else
709fac60a5Sjoris 		out = current_cvsroot->cr_srvin;
719fac60a5Sjoris 
729fac60a5Sjoris 	fputs(data, out);
739fac60a5Sjoris 	fputs("\n", out);
7400b139a2Stobias 
7500b139a2Stobias 	if (cvs_server_active == 0 && cvs_client_inlog_fd != -1) {
76bb59aeccStobias 		len = strlen(data);
77bb59aeccStobias 		if (atomicio(vwrite, cvs_client_inlog_fd, data, len) != len ||
78bb59aeccStobias 		    atomicio(vwrite, cvs_client_inlog_fd, &nl, 1) != 1)
79bb59aeccStobias 			fatal("failed to write to log file");
8000b139a2Stobias 	}
819fac60a5Sjoris }
829fac60a5Sjoris 
839fac60a5Sjoris char *
cvs_remote_input(void)849fac60a5Sjoris cvs_remote_input(void)
859fac60a5Sjoris {
869fac60a5Sjoris 	FILE *in;
879fac60a5Sjoris 	size_t len;
8800b139a2Stobias 	char nl = '\n';
899fac60a5Sjoris 	char *data, *ldata;
909fac60a5Sjoris 
919fac60a5Sjoris 	if (cvs_server_active)
929fac60a5Sjoris 		in = stdin;
939fac60a5Sjoris 	else
949fac60a5Sjoris 		in = current_cvsroot->cr_srvout;
959fac60a5Sjoris 
969fac60a5Sjoris 	data = fgetln(in, &len);
979fac60a5Sjoris 	if (data == NULL) {
989fac60a5Sjoris 		if (sig_received != 0)
999fac60a5Sjoris 			fatal("received signal %d", sig_received);
1009fac60a5Sjoris 
1019fac60a5Sjoris 		if (cvs_server_active) {
1029fac60a5Sjoris 			cvs_cleanup();
1039fac60a5Sjoris 			exit(0);
1049fac60a5Sjoris 		}
1059fac60a5Sjoris 
1069fac60a5Sjoris 		fatal("the connection has been closed by the server");
1079fac60a5Sjoris 	}
1089fac60a5Sjoris 
1099fac60a5Sjoris 	if (data[len - 1] == '\n') {
1109fac60a5Sjoris 		data[len - 1] = '\0';
111a4e8257aSotto 		ldata = xstrdup(data);
1129fac60a5Sjoris 	} else {
1139fac60a5Sjoris 		ldata = xmalloc(len + 1);
114a4e8257aSotto 		memcpy(ldata, data, len);
115a4e8257aSotto 		ldata[len] = '\0';
1169fac60a5Sjoris 	}
1179fac60a5Sjoris 
11844001a5bSjoris 	if (cvs_server_active == 0 && cvs_client_outlog_fd != -1) {
119bb59aeccStobias 		len = strlen(data);
120bb59aeccStobias 		if (atomicio(vwrite, cvs_client_outlog_fd, data, len) != len ||
121bb59aeccStobias 		    atomicio(vwrite, cvs_client_outlog_fd, &nl, 1) != 1)
122bb59aeccStobias 			fatal("failed to write to log file");
12344001a5bSjoris 	}
12444001a5bSjoris 
1259fac60a5Sjoris 	return (ldata);
1269fac60a5Sjoris }
1279fac60a5Sjoris 
128bb510330Sjoris void
cvs_remote_receive_file(int fd,size_t len)129bb510330Sjoris cvs_remote_receive_file(int fd, size_t len)
1309fac60a5Sjoris {
1319fac60a5Sjoris 	FILE *in;
132*1a0afcdeSderaadt 	char data[_MAXBSIZE];
133bb59aeccStobias 	size_t nread, nleft, toread;
1349fac60a5Sjoris 
1359fac60a5Sjoris 	if (cvs_server_active)
1369fac60a5Sjoris 		in = stdin;
1379fac60a5Sjoris 	else
1389fac60a5Sjoris 		in = current_cvsroot->cr_srvout;
1399fac60a5Sjoris 
140bb510330Sjoris 	nleft = len;
141af48f1c1Sjoris 
142bb510330Sjoris 	while (nleft > 0) {
143*1a0afcdeSderaadt 		toread = MINIMUM(nleft, sizeof data);
144bb510330Sjoris 
145bb510330Sjoris 		nread = fread(data, sizeof(char), toread, in);
146bb510330Sjoris 		if (nread == 0)
147bb510330Sjoris 			fatal("error receiving file");
148bb510330Sjoris 
149bb59aeccStobias 		if (atomicio(vwrite, fd, data, nread) != nread)
1503be7c8b5Sotto 			fatal("failed to write %zu bytes", nread);
151bb510330Sjoris 
152bb59aeccStobias 		if (cvs_server_active == 0 && cvs_client_outlog_fd != -1 &&
153bb59aeccStobias 		    atomicio(vwrite, cvs_client_outlog_fd, data, nread)
154bb59aeccStobias 		    != nread)
155bb59aeccStobias 			fatal("failed to write to log file");
156bb510330Sjoris 
157bb510330Sjoris 		nleft -= nread;
158bb510330Sjoris 	}
159af48f1c1Sjoris }
160af48f1c1Sjoris 
1619fac60a5Sjoris void
cvs_remote_send_file(const char * path,int _fd)1622e0d696aSjoris cvs_remote_send_file(const char *path, int _fd)
1639fac60a5Sjoris {
164c486465dSxsa 	int fd;
165bb510330Sjoris 	FILE *out, *in;
1663be7c8b5Sotto 	size_t ret, rw;
1673be7c8b5Sotto 	off_t total;
1689fac60a5Sjoris 	struct stat st;
169*1a0afcdeSderaadt 	char buf[18], data[_MAXBSIZE];
1709fac60a5Sjoris 
1719fac60a5Sjoris 	if (cvs_server_active)
1729fac60a5Sjoris 		out = stdout;
1739fac60a5Sjoris 	else
1749fac60a5Sjoris 		out = current_cvsroot->cr_srvin;
1759fac60a5Sjoris 
1762e0d696aSjoris 	fd = dup(_fd);
1772e0d696aSjoris 	if (fd == -1)
1782e0d696aSjoris 		fatal("cvs_remote_send_file: dup: %s", strerror(errno));
1792e0d696aSjoris 
1803aaa63ebSderaadt 	if (lseek(fd, 0, SEEK_SET) == -1)
1812e0d696aSjoris 		fatal("cvs_remote_send_file: %s: lseek: %s", path,
1822e0d696aSjoris 		    strerror(errno));
1839fac60a5Sjoris 
1849fac60a5Sjoris 	if (fstat(fd, &st) == -1)
1852e0d696aSjoris 		fatal("cvs_remote_send_file: %s: fstat: %s", path,
1862e0d696aSjoris 		    strerror(errno));
1879fac60a5Sjoris 
1889fac60a5Sjoris 	cvs_modetostr(st.st_mode, buf, sizeof(buf));
1899fac60a5Sjoris 	cvs_remote_output(buf);
1909fac60a5Sjoris 
191c486465dSxsa 	(void)xsnprintf(buf, sizeof(buf), "%lld", st.st_size);
1929fac60a5Sjoris 	cvs_remote_output(buf);
1939fac60a5Sjoris 
194bb510330Sjoris 	if ((in = fdopen(fd, "r")) == NULL)
195bb510330Sjoris 		fatal("cvs_remote_send_file: fdopen %s", strerror(errno));
19644001a5bSjoris 
197bb510330Sjoris 	total = 0;
198*1a0afcdeSderaadt 	while ((ret = fread(data, sizeof(char), sizeof data, in)) != 0) {
199bb510330Sjoris 		rw = fwrite(data, sizeof(char), ret, out);
200bb510330Sjoris 		if (rw != ret)
2013be7c8b5Sotto 			fatal("failed to write %zu bytes", ret);
202bb510330Sjoris 
203bb59aeccStobias 		if (cvs_server_active == 0 && cvs_client_inlog_fd != -1 &&
204bb59aeccStobias 		    atomicio(vwrite, cvs_client_inlog_fd, data, ret) != ret)
205bb59aeccStobias 			fatal("failed to write to log file");
206bb510330Sjoris 
207bb510330Sjoris 		total += ret;
20844001a5bSjoris 	}
20944001a5bSjoris 
210bb510330Sjoris 	if (total != st.st_size)
2113be7c8b5Sotto 		fatal("length mismatch, %lld vs %lld", total, st.st_size);
212af48f1c1Sjoris 
213bb510330Sjoris 	(void)fclose(in);
2149fac60a5Sjoris }
2159fac60a5Sjoris 
2169fac60a5Sjoris void
cvs_remote_send_file_buf(char * file,BUF * bp,mode_t mode)2171b5598b0Sjoris cvs_remote_send_file_buf(char *file, BUF *bp, mode_t mode)
2181b5598b0Sjoris {
2191b5598b0Sjoris 	char buf[18];
2201b5598b0Sjoris 	u_char *data;
2211b5598b0Sjoris 	size_t len, ret;
2221b5598b0Sjoris 
2231b5598b0Sjoris 	if (cvs_server_active != 1)
2241b5598b0Sjoris 		fatal("cvs_remote_send_file_buf is server only");
2251b5598b0Sjoris 
2267bb3ddb0Sray 	len = buf_len(bp);
2277bb3ddb0Sray 	data = buf_release(bp);
2281b5598b0Sjoris 
2291b5598b0Sjoris 	cvs_modetostr(mode, buf, sizeof(buf));
2301b5598b0Sjoris 	cvs_remote_output(buf);
2311b5598b0Sjoris 
2321b5598b0Sjoris 	(void)xsnprintf(buf, sizeof(buf), "%ld", len);
2331b5598b0Sjoris 	cvs_remote_output(buf);
2341b5598b0Sjoris 
2351b5598b0Sjoris 	ret = fwrite(data, sizeof(char), len, stdout);
2361b5598b0Sjoris 	if (ret != len)
2371b5598b0Sjoris 		cvs_log(LP_ERR, "warning: sent %s truncated", file);
2381b5598b0Sjoris 
2391b5598b0Sjoris 	if (cvs_server_active == 0 && cvs_client_inlog_fd != -1 &&
2401b5598b0Sjoris 	    atomicio(vwrite, cvs_client_inlog_fd, data, len) != len)
2411b5598b0Sjoris 		fatal("failed to write to log file");
2421b5598b0Sjoris 
243397ddb8aSnicm 	free(data);
2441b5598b0Sjoris }
2451b5598b0Sjoris 
2461b5598b0Sjoris void
cvs_remote_classify_file(struct cvs_file * cf)2479fac60a5Sjoris cvs_remote_classify_file(struct cvs_file *cf)
2489fac60a5Sjoris {
2499fac60a5Sjoris 	struct stat st;
2509fac60a5Sjoris 	CVSENTRIES *entlist;
2519fac60a5Sjoris 
2529fac60a5Sjoris 	entlist = cvs_ent_open(cf->file_wd);
2539fac60a5Sjoris 	cf->file_ent = cvs_ent_get(entlist, cf->file_name);
2549fac60a5Sjoris 
2559fac60a5Sjoris 	if (cf->file_ent != NULL && cf->file_ent->ce_status != CVS_ENT_REG) {
2568fa21b37Sjoris 		if (cf->file_ent->ce_status == CVS_ENT_ADDED) {
2578fa21b37Sjoris 			if (cf->fd != -1)
2589fac60a5Sjoris 				cf->file_status = FILE_ADDED;
2599fac60a5Sjoris 			else
2608fa21b37Sjoris 				cf->file_status = FILE_UNKNOWN;
2618fa21b37Sjoris 		} else {
2629fac60a5Sjoris 			cf->file_status = FILE_REMOVED;
2638fa21b37Sjoris 		}
2648fa21b37Sjoris 
2659fac60a5Sjoris 		return;
2669fac60a5Sjoris 	}
2679fac60a5Sjoris 
268627b103eSjoris 	if (cf->file_ent != NULL) {
269627b103eSjoris 		if (cf->file_ent->ce_type == CVS_ENT_DIR)
270627b103eSjoris 			cf->file_type = CVS_DIR;
271627b103eSjoris 		else
272627b103eSjoris 			cf->file_type = CVS_FILE;
273627b103eSjoris 	}
274627b103eSjoris 
2755cf15c45Sjoris 	if (cf->fd != -1)
2765cf15c45Sjoris 		cf->file_flags |= FILE_ON_DISK;
2775cf15c45Sjoris 
2785cf15c45Sjoris 	if ((cf->file_flags & FILE_ON_DISK) && cf->file_ent != NULL) {
2799fac60a5Sjoris 		if (fstat(cf->fd, &st) == -1)
2809fac60a5Sjoris 			fatal("cvs_remote_classify_file(%s): %s", cf->file_path,
2819fac60a5Sjoris 			    strerror(errno));
2829fac60a5Sjoris 
28383a98125Sjoris 		if (st.st_mtime != cf->file_ent->ce_mtime ||
28483a98125Sjoris 		    cf->file_ent->ce_conflict != NULL)
2859fac60a5Sjoris 			cf->file_status = FILE_MODIFIED;
2869fac60a5Sjoris 		else
2879fac60a5Sjoris 			cf->file_status = FILE_UPTODATE;
2885cf15c45Sjoris 	} else if (!(cf->file_flags & FILE_ON_DISK)) {
2899fac60a5Sjoris 		cf->file_status = FILE_UNKNOWN;
2909fac60a5Sjoris 	}
29127de14f8Sjoris 
29227de14f8Sjoris 	if (cvs_cmdop == CVS_OP_IMPORT && cf->file_type == CVS_FILE)
29327de14f8Sjoris 		cf->file_status = FILE_MODIFIED;
2949fac60a5Sjoris }
2959fac60a5Sjoris 
29638be6170Sjoris 
29738be6170Sjoris void
cvs_validate_directory(const char * path)29838be6170Sjoris cvs_validate_directory(const char *path)
29938be6170Sjoris {
30038be6170Sjoris 	char *dir, *sp, *dp;
30138be6170Sjoris 
30238be6170Sjoris 	dir = xstrdup(path);
3032dbb26f2Sjoris 
30438be6170Sjoris 	for (sp = dir; sp != NULL; sp = dp) {
30538be6170Sjoris 		dp = strchr(sp, '/');
30638be6170Sjoris 		if (dp != NULL)
30738be6170Sjoris 			*(dp++) = '\0';
30838be6170Sjoris 
30938be6170Sjoris 		if (!strcmp(sp, ".."))
31038be6170Sjoris 			fatal("path validation failed!");
31138be6170Sjoris 	}
31238be6170Sjoris 
313397ddb8aSnicm 	free(dir);
31438be6170Sjoris }
315