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