Annotation of src/usr.bin/rsync/ids.c, Revision 1.7
1.7 ! benno 1: /* $Id: ids.c,v 1.6 2019/02/21 22:06:26 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>
1.5 florian 20: #include <pwd.h>
1.1 benno 21: #include <stdio.h>
22: #include <stdlib.h>
23: #include <string.h>
24: #include <unistd.h>
25:
26: #include "extern.h"
27:
28: /*
29: * Free a list of struct ident previously allocated with idents_gid_add().
30: * Does nothing if the pointer is NULL.
31: */
32: void
33: idents_free(struct ident *p, size_t sz)
34: {
35: size_t i;
36:
1.3 benno 37: if (p == NULL)
1.1 benno 38: return;
39: for (i = 0; i < sz; i++)
40: free(p[i].name);
41: free(p);
42: }
43:
44: /*
1.5 florian 45: * Given a list of files with the identifiers as set by the sender,
46: * re-assign the identifiers from the list of remapped ones.
47: * Don't ever remap wheel/root.
1.3 benno 48: */
49: void
1.5 florian 50: idents_assign_gid(struct sess *sess, struct flist *fl, size_t flsz,
51: const struct ident *ids, size_t idsz)
1.3 benno 52: {
53: size_t i, j;
54:
1.7 ! benno 55: assert(!sess->opts->numeric_ids);
! 56:
1.3 benno 57: for (i = 0; i < flsz; i++) {
1.5 florian 58: if (fl[i].st.gid == 0)
1.3 benno 59: continue;
1.5 florian 60: for (j = 0; j < idsz; j++)
61: if ((int32_t)fl[i].st.gid == ids[j].id)
1.3 benno 62: break;
1.5 florian 63: assert(j < idsz);
64: fl[i].st.gid = ids[j].mapped;
1.3 benno 65: }
66: }
67:
68: /*
1.5 florian 69: * Like idents_assign_gid().
70: */
71: void
72: idents_assign_uid(struct sess *sess, struct flist *fl, size_t flsz,
73: const struct ident *ids, size_t idsz)
74: {
75: size_t i, j;
76:
1.7 ! benno 77: assert(!sess->opts->numeric_ids);
! 78:
1.5 florian 79: for (i = 0; i < flsz; i++) {
80: if (fl[i].st.uid == 0)
81: continue;
82: for (j = 0; j < idsz; j++)
83: if ((int32_t)fl[i].st.uid == ids[j].id)
84: break;
85: assert(j < idsz);
86: fl[i].st.uid = ids[j].mapped;
87: }
88: }
89:
90: /*
91: * Given a list of identifiers from the remote host, fill in our local
1.1 benno 92: * identifiers of the same names.
1.6 benno 93: * Use the remote numeric identifier if we can't find the identifier OR the
94: * identifier is zero (wheel/root).
95: * FIXME: we should at least warn when we can't find an identifier, use
96: * the numeric id, and that numeric id is assigned to a different user.
1.1 benno 97: */
98: void
1.5 florian 99: idents_remap(struct sess *sess, int isgid, struct ident *ids, size_t idsz)
1.1 benno 100: {
1.4 benno 101: size_t i;
1.1 benno 102: struct group *grp;
1.5 florian 103: struct passwd *usr;
104: int32_t id;
1.6 benno 105:
1.7 ! benno 106: assert(!sess->opts->numeric_ids);
1.1 benno 107:
1.5 florian 108: for (i = 0; i < idsz; i++) {
109: assert(ids[i].id != 0);
110:
111: /* Start by getting our local representation. */
112:
113: if (isgid)
114: id = (grp = getgrnam(ids[i].name)) == NULL ?
115: -1 : grp->gr_gid;
116: else
117: id = (usr = getpwnam(ids[i].name)) == NULL ?
118: -1 : usr->pw_uid;
1.3 benno 119:
1.4 benno 120: /*
1.3 benno 121: * (1) Empty names inherit.
1.5 florian 122: * (2) Unknown identifier names inherit.
123: * (3) Wheel/root inherits.
1.3 benno 124: * (4) Otherwise, use the local identifier.
125: */
126:
1.5 florian 127: if (ids[i].name[0] == '\0')
128: ids[i].mapped = ids[i].id;
129: else if (id <= 0)
130: ids[i].mapped = ids[i].id;
1.1 benno 131: else
1.5 florian 132: ids[i].mapped = id;
1.2 benno 133:
1.5 florian 134: LOG4(sess, "remapped identifier %s: %" PRId32 " -> %" PRId32,
135: ids[i].name, ids[i].id, ids[i].mapped);
1.1 benno 136: }
137: }
138:
139: /*
1.5 florian 140: * If "id" is not part of the list of known users or groups (depending
141: * upon "isgid", add it.
142: * This also verifies that the name isn't too long.
143: * Does nothing with user/group zero.
1.1 benno 144: * Return zero on failure, non-zero on success.
145: */
146: int
1.5 florian 147: idents_add(struct sess *sess, int isgid,
148: struct ident **ids, size_t *idsz, int32_t id)
1.1 benno 149: {
150: struct group *grp;
1.5 florian 151: struct passwd *usr;
1.1 benno 152: size_t i, sz;
153: void *pp;
1.5 florian 154: const char *name;
1.1 benno 155:
1.5 florian 156: if (id == 0)
1.3 benno 157: return 1;
158:
1.5 florian 159: for (i = 0; i < *idsz; i++)
160: if ((*ids)[i].id == id)
1.1 benno 161: return 1;
162:
1.4 benno 163: /*
1.5 florian 164: * Look up the reference in a type-specific way.
165: * Make sure that the name length is sane: we transmit it using
166: * a single byte.
1.1 benno 167: */
168:
1.5 florian 169: assert(i == *idsz);
170: if (isgid) {
171: if ((grp = getgrgid((gid_t)id)) == NULL) {
172: ERR(sess, "%" PRId32 ": unknown gid", id);
173: return 0;
174: }
175: name = grp->gr_name;
176: } else {
177: if ((usr = getpwuid((uid_t)id)) == NULL) {
178: ERR(sess, "%" PRId32 ": unknown uid", id);
179: return 0;
180: }
181: name = usr->pw_name;
182: }
183:
184: if ((sz = strlen(name)) > UINT8_MAX) {
185: ERRX(sess, "%" PRId32 ": name too long: %s", id, name);
1.1 benno 186: return 0;
1.3 benno 187: } else if (sz == 0) {
1.5 florian 188: ERRX(sess, "%" PRId32 ": zero-length name", id);
1.1 benno 189: return 0;
190: }
191:
1.5 florian 192: /* Add the identifier to the array. */
1.1 benno 193:
1.5 florian 194: pp = reallocarray(*ids, *idsz + 1, sizeof(struct ident));
1.3 benno 195: if (pp == NULL) {
1.1 benno 196: ERR(sess, "reallocarray");
197: return 0;
198: }
1.5 florian 199: *ids = pp;
200: (*ids)[*idsz].id = id;
201: (*ids)[*idsz].name = strdup(name);
202: if ((*ids)[*idsz].name == NULL) {
1.1 benno 203: ERR(sess, "strdup");
204: return 0;
205: }
206:
1.5 florian 207: LOG4(sess, "adding identifier to list: %s (%u)",
208: (*ids)[*idsz].name, (*ids)[*idsz].id);
209: (*idsz)++;
1.1 benno 210: return 1;
211: }
212:
213: /*
214: * Send a list of struct ident.
215: * See idents_recv().
216: * We should only do this if we're preserving gids/uids.
217: * Return zero on failure, non-zero on success.
218: */
219: int
1.4 benno 220: idents_send(struct sess *sess,
1.1 benno 221: int fd, const struct ident *ids, size_t idsz)
222: {
223: size_t i, sz;
224:
225: for (i = 0; i < idsz; i++) {
1.3 benno 226: assert(ids[i].name != NULL);
227: assert(ids[i].id != 0);
1.1 benno 228: sz = strlen(ids[i].name);
229: assert(sz > 0 && sz <= UINT8_MAX);
230: if (!io_write_int(sess, fd, ids[i].id)) {
231: ERRX1(sess, "io_write_int");
232: return 0;
233: } else if (!io_write_byte(sess, fd, sz)) {
234: ERRX1(sess, "io_write_byte");
235: return 0;
236: } else if (!io_write_buf(sess, fd, ids[i].name, sz)) {
237: ERRX1(sess, "io_write_byte");
238: return 0;
239: }
240: }
241:
242: if (!io_write_int(sess, fd, 0)) {
243: ERRX1(sess, "io_write_int");
244: return 0;
245: }
246:
247: return 1;
248: }
249:
250: /*
251: * Receive a list of struct ident.
252: * See idents_send().
253: * We should only do this if we're preserving gids/uids.
254: * Return zero on failure, non-zero on success.
255: */
256: int
257: idents_recv(struct sess *sess,
258: int fd, struct ident **ids, size_t *idsz)
259: {
260: int32_t id;
261: uint8_t sz;
262: void *pp;
263:
264: for (;;) {
265: if (!io_read_int(sess, fd, &id)) {
266: ERRX1(sess, "io_read_int");
267: return 0;
1.3 benno 268: } else if (id == 0)
1.1 benno 269: break;
1.4 benno 270:
271: pp = reallocarray(*ids,
1.1 benno 272: *idsz + 1, sizeof(struct ident));
1.3 benno 273: if (pp == NULL) {
1.1 benno 274: ERR(sess, "reallocarray");
275: return 0;
276: }
277: *ids = pp;
278: memset(&(*ids)[*idsz], 0, sizeof(struct ident));
1.3 benno 279:
280: /*
1.5 florian 281: * When reading the size, warn if we get a size of zero.
1.3 benno 282: * The spec doesn't allow this, but we might have a
283: * noncomformant or adversarial sender.
284: */
285:
1.1 benno 286: if (!io_read_byte(sess, fd, &sz)) {
287: ERRX1(sess, "io_read_byte");
288: return 0;
1.5 florian 289: } else if (sz == 0)
290: WARNX(sess, "zero-length name "
291: "in identifier list");
1.3 benno 292:
1.1 benno 293: (*ids)[*idsz].id = id;
294: (*ids)[*idsz].name = calloc(sz + 1, 1);
1.3 benno 295: if ((*ids)[*idsz].name == NULL) {
1.1 benno 296: ERR(sess, "calloc");
297: return 0;
298: }
299: if (!io_read_buf(sess, fd, (*ids)[*idsz].name, sz)) {
300: ERRX1(sess, "io_read_buf");
301: return 0;
302: }
303: (*idsz)++;
304: }
305:
306: return 1;
307: }