Annotation of src/usr.bin/rsync/ids.c, Revision 1.4
1.4 ! benno 1: /* $Id: ids.c,v 1.3 2019/02/12 19:13:03 benno Exp $ */
1.1 benno 2: /*
3: * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: */
17: #include <assert.h>
18: #include <grp.h>
19: #include <inttypes.h>
20: #include <stdio.h>
21: #include <stdlib.h>
22: #include <string.h>
23: #include <unistd.h>
24:
25: #include "extern.h"
26:
27: /*
28: * Free a list of struct ident previously allocated with idents_gid_add().
29: * Does nothing if the pointer is NULL.
30: */
31: void
32: idents_free(struct ident *p, size_t sz)
33: {
34: size_t i;
35:
1.3 benno 36: if (p == NULL)
1.1 benno 37: return;
38: for (i = 0; i < sz; i++)
39: free(p[i].name);
40: free(p);
41: }
42:
43: /*
1.3 benno 44: * Given a list of files with the groups as set by the sender, re-assign
45: * the groups from the list of remapped group identifiers.
46: * Don't ever remap group wheel.
47: */
48: void
49: idents_gid_assign(struct sess *sess, struct flist *fl, size_t flsz,
50: const struct ident *gids, size_t gidsz)
51: {
52: size_t i, j;
53:
54: for (i = 0; i < flsz; i++) {
55: if (0 == fl[i].st.gid)
56: continue;
57: for (j = 0; j < gidsz; j++)
58: if ((int32_t)fl[i].st.gid == gids[j].id)
59: break;
60: assert(j < gidsz);
61: fl[i].st.gid = gids[j].mapped;
62: }
63: }
64:
65: /*
1.1 benno 66: * Given a list of groups from the remote host, fill in our local
67: * identifiers of the same names.
68: * Use the remote numeric identifier if we can't find the group OR the
69: * group has identifier zero.
1.2 benno 70: * FIXME: what happens if we don't find the local group (we should
71: * really warn about this), but the remote group identifier maps into a
72: * different group name for us?
73: * These are pretty unexpected things for rsync to do.
74: * Another FIXME because we shouldn't let that happen even though the
75: * reference rsync does.
1.1 benno 76: */
77: void
78: idents_gid_remap(struct sess *sess, struct ident *gids, size_t gidsz)
79: {
1.4 ! benno 80: size_t i;
1.1 benno 81: struct group *grp;
82:
83: for (i = 0; i < gidsz; i++) {
1.3 benno 84: assert(gids[i].id != 0);
85:
1.4 ! benno 86: /*
1.3 benno 87: * (1) Empty names inherit.
88: * (2) Unknown group names inherit.
89: * (3) Group wheel inherits.
90: * (4) Otherwise, use the local identifier.
91: */
92:
93: if (gids[i].name[0] == '\0')
1.1 benno 94: gids[i].mapped = gids[i].id;
1.3 benno 95: else if ((grp = getgrnam(gids[i].name)) == NULL)
96: gids[i].mapped = gids[i].id;
97: else if (grp->gr_gid == 0)
1.1 benno 98: gids[i].mapped = gids[i].id;
99: else
100: gids[i].mapped = grp->gr_gid;
1.2 benno 101:
1.1 benno 102: LOG4(sess, "remapped group %s: %" PRId32 " -> %" PRId32,
103: gids[i].name, gids[i].id, gids[i].mapped);
104: }
105: }
106:
107: /*
108: * If "gid" is not part of the list of known groups, add it.
109: * This also verifies that the group name isn't too long.
1.3 benno 110: * Does nothing with group zero.
1.1 benno 111: * Return zero on failure, non-zero on success.
112: */
113: int
114: idents_gid_add(struct sess *sess, struct ident **gids, size_t *gidsz, gid_t gid)
115: {
116: struct group *grp;
117: size_t i, sz;
118: void *pp;
119:
1.3 benno 120: if (gid == 0)
121: return 1;
122:
1.1 benno 123: for (i = 0; i < *gidsz; i++)
124: if ((*gids)[i].id == (int32_t)gid)
125: return 1;
126:
1.4 ! benno 127: /*
1.1 benno 128: * Look us up in /etc/group.
129: * Make sure that the group name length is sane: we transmit it
130: * using a single byte.
131: */
132:
133: assert(i == *gidsz);
1.3 benno 134: if ((grp = getgrgid(gid)) == NULL) {
1.1 benno 135: ERR(sess, "%u: unknown gid", gid);
136: return 0;
137: } else if ((sz = strlen(grp->gr_name)) > UINT8_MAX) {
138: ERRX(sess, "%u: group name too long: %s", gid, grp->gr_name);
139: return 0;
1.3 benno 140: } else if (sz == 0) {
1.1 benno 141: ERRX(sess, "%u: group name zero-length", gid);
142: return 0;
143: }
144:
145: /* Add the group to the array. */
146:
147: pp = reallocarray(*gids, *gidsz + 1, sizeof(struct ident));
1.3 benno 148: if (pp == NULL) {
1.1 benno 149: ERR(sess, "reallocarray");
150: return 0;
151: }
152: *gids = pp;
153: (*gids)[*gidsz].id = gid;
154: (*gids)[*gidsz].name = strdup(grp->gr_name);
155: if (NULL == (*gids)[*gidsz].name) {
156: ERR(sess, "strdup");
157: return 0;
158: }
159:
1.4 ! benno 160: LOG4(sess, "adding group to list: %s (%u)",
1.1 benno 161: (*gids)[*gidsz].name, (*gids)[*gidsz].id);
162: (*gidsz)++;
163: return 1;
164: }
165:
166: /*
167: * Send a list of struct ident.
168: * See idents_recv().
169: * We should only do this if we're preserving gids/uids.
170: * Return zero on failure, non-zero on success.
171: */
172: int
1.4 ! benno 173: idents_send(struct sess *sess,
1.1 benno 174: int fd, const struct ident *ids, size_t idsz)
175: {
176: size_t i, sz;
177:
178: for (i = 0; i < idsz; i++) {
1.3 benno 179: assert(ids[i].name != NULL);
180: assert(ids[i].id != 0);
1.1 benno 181: sz = strlen(ids[i].name);
182: assert(sz > 0 && sz <= UINT8_MAX);
183: if (!io_write_int(sess, fd, ids[i].id)) {
184: ERRX1(sess, "io_write_int");
185: return 0;
186: } else if (!io_write_byte(sess, fd, sz)) {
187: ERRX1(sess, "io_write_byte");
188: return 0;
189: } else if (!io_write_buf(sess, fd, ids[i].name, sz)) {
190: ERRX1(sess, "io_write_byte");
191: return 0;
192: }
193: }
194:
195: if (!io_write_int(sess, fd, 0)) {
196: ERRX1(sess, "io_write_int");
197: return 0;
198: }
199:
200: return 1;
201: }
202:
203: /*
204: * Receive a list of struct ident.
205: * See idents_send().
206: * We should only do this if we're preserving gids/uids.
207: * Return zero on failure, non-zero on success.
208: */
209: int
210: idents_recv(struct sess *sess,
211: int fd, struct ident **ids, size_t *idsz)
212: {
213: int32_t id;
214: uint8_t sz;
215: void *pp;
216:
217: for (;;) {
218: if (!io_read_int(sess, fd, &id)) {
219: ERRX1(sess, "io_read_int");
220: return 0;
1.3 benno 221: } else if (id == 0)
1.1 benno 222: break;
1.4 ! benno 223:
! 224: pp = reallocarray(*ids,
1.1 benno 225: *idsz + 1, sizeof(struct ident));
1.3 benno 226: if (pp == NULL) {
1.1 benno 227: ERR(sess, "reallocarray");
228: return 0;
229: }
230: *ids = pp;
231: memset(&(*ids)[*idsz], 0, sizeof(struct ident));
1.3 benno 232:
233: /*
234: * When reading the size, warn if we get a group size of
235: * zero.
236: * The spec doesn't allow this, but we might have a
237: * noncomformant or adversarial sender.
238: */
239:
1.1 benno 240: if (!io_read_byte(sess, fd, &sz)) {
241: ERRX1(sess, "io_read_byte");
242: return 0;
1.3 benno 243: } else if (0 == sz)
244: WARNX(sess, "zero-length group name "
245: "in group list");
246:
1.1 benno 247: (*ids)[*idsz].id = id;
248: (*ids)[*idsz].name = calloc(sz + 1, 1);
1.3 benno 249: if ((*ids)[*idsz].name == NULL) {
1.1 benno 250: ERR(sess, "calloc");
251: return 0;
252: }
253: if (!io_read_buf(sess, fd, (*ids)[*idsz].name, sz)) {
254: ERRX1(sess, "io_read_buf");
255: return 0;
256: }
257: (*idsz)++;
258: }
259:
260: return 1;
261: }