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