Annotation of src/usr.bin/rsync/ids.c, Revision 1.2
1.2 ! benno 1: /* $Id: ids.c,v 1.1 2019/02/12 19:08:29 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:
36: if (NULL == p)
37: return;
38: for (i = 0; i < sz; i++)
39: free(p[i].name);
40: free(p);
41: }
42:
43: /*
44: * Given a list of groups from the remote host, fill in our local
45: * identifiers of the same names.
46: * Use the remote numeric identifier if we can't find the group OR the
47: * group has identifier zero.
1.2 ! benno 48: * FIXME: what happens if we don't find the local group (we should
! 49: * really warn about this), but the remote group identifier maps into a
! 50: * different group name for us?
! 51: * These are pretty unexpected things for rsync to do.
! 52: * Another FIXME because we shouldn't let that happen even though the
! 53: * reference rsync does.
1.1 benno 54: */
55: void
56: idents_gid_remap(struct sess *sess, struct ident *gids, size_t gidsz)
57: {
58: size_t i;
59: struct group *grp;
60:
61: for (i = 0; i < gidsz; i++) {
62: if (NULL == (grp = getgrnam(gids[i].name)))
63: gids[i].mapped = gids[i].id;
64: else if (0 == grp->gr_gid)
65: gids[i].mapped = gids[i].id;
66: else
67: gids[i].mapped = grp->gr_gid;
1.2 ! benno 68:
1.1 benno 69: LOG4(sess, "remapped group %s: %" PRId32 " -> %" PRId32,
70: gids[i].name, gids[i].id, gids[i].mapped);
71: }
72: }
73:
74: /*
75: * If "gid" is not part of the list of known groups, add it.
76: * This also verifies that the group name isn't too long.
77: * Return zero on failure, non-zero on success.
78: */
79: int
80: idents_gid_add(struct sess *sess, struct ident **gids, size_t *gidsz, gid_t gid)
81: {
82: struct group *grp;
83: size_t i, sz;
84: void *pp;
85:
86: for (i = 0; i < *gidsz; i++)
87: if ((*gids)[i].id == (int32_t)gid)
88: return 1;
89:
90: /*
91: * Look us up in /etc/group.
92: * Make sure that the group name length is sane: we transmit it
93: * using a single byte.
94: */
95:
96: assert(i == *gidsz);
97: if (NULL == (grp = getgrgid(gid))) {
98: ERR(sess, "%u: unknown gid", gid);
99: return 0;
100: } else if ((sz = strlen(grp->gr_name)) > UINT8_MAX) {
101: ERRX(sess, "%u: group name too long: %s", gid, grp->gr_name);
102: return 0;
103: } else if (0 == sz) {
104: ERRX(sess, "%u: group name zero-length", gid);
105: return 0;
106: }
107:
108: /* Add the group to the array. */
109:
110: pp = reallocarray(*gids, *gidsz + 1, sizeof(struct ident));
111: if (NULL == pp) {
112: ERR(sess, "reallocarray");
113: return 0;
114: }
115: *gids = pp;
116: (*gids)[*gidsz].id = gid;
117: (*gids)[*gidsz].name = strdup(grp->gr_name);
118: if (NULL == (*gids)[*gidsz].name) {
119: ERR(sess, "strdup");
120: return 0;
121: }
122:
123: LOG4(sess, "adding group to list: %s (%u)",
124: (*gids)[*gidsz].name, (*gids)[*gidsz].id);
125: (*gidsz)++;
126: return 1;
127: }
128:
129: /*
130: * Send a list of struct ident.
131: * See idents_recv().
132: * We should only do this if we're preserving gids/uids.
133: * Return zero on failure, non-zero on success.
134: */
135: int
136: idents_send(struct sess *sess,
137: int fd, const struct ident *ids, size_t idsz)
138: {
139: size_t i, sz;
140:
141: for (i = 0; i < idsz; i++) {
142: assert(NULL != ids[i].name);
143: sz = strlen(ids[i].name);
144: assert(sz > 0 && sz <= UINT8_MAX);
145: if (!io_write_int(sess, fd, ids[i].id)) {
146: ERRX1(sess, "io_write_int");
147: return 0;
148: } else if (!io_write_byte(sess, fd, sz)) {
149: ERRX1(sess, "io_write_byte");
150: return 0;
151: } else if (!io_write_buf(sess, fd, ids[i].name, sz)) {
152: ERRX1(sess, "io_write_byte");
153: return 0;
154: }
155: }
156:
157: if (!io_write_int(sess, fd, 0)) {
158: ERRX1(sess, "io_write_int");
159: return 0;
160: }
161:
162: return 1;
163: }
164:
165: /*
166: * Receive a list of struct ident.
167: * See idents_send().
168: * We should only do this if we're preserving gids/uids.
169: * Return zero on failure, non-zero on success.
170: */
171: int
172: idents_recv(struct sess *sess,
173: int fd, struct ident **ids, size_t *idsz)
174: {
175: int32_t id;
176: uint8_t sz;
177: void *pp;
178:
179: for (;;) {
180: if (!io_read_int(sess, fd, &id)) {
181: ERRX1(sess, "io_read_int");
182: return 0;
183: } else if (0 == id)
184: break;
185:
186: pp = reallocarray(*ids,
187: *idsz + 1, sizeof(struct ident));
188: if (NULL == pp) {
189: ERR(sess, "reallocarray");
190: return 0;
191: }
192: *ids = pp;
193: memset(&(*ids)[*idsz], 0, sizeof(struct ident));
194: if (!io_read_byte(sess, fd, &sz)) {
195: ERRX1(sess, "io_read_byte");
196: return 0;
197: }
198: (*ids)[*idsz].id = id;
199: (*ids)[*idsz].name = calloc(sz + 1, 1);
200: if (NULL == (*ids)[*idsz].name) {
201: ERR(sess, "calloc");
202: return 0;
203: }
204: if (!io_read_buf(sess, fd, (*ids)[*idsz].name, sz)) {
205: ERRX1(sess, "io_read_buf");
206: return 0;
207: }
208: (*idsz)++;
209: }
210:
211: return 1;
212: }