Annotation of src/usr.bin/rsync/ids.c, Revision 1.11
1.11 ! deraadt 1: /* $Id: ids.c,v 1.10 2019/03/30 07:24:02 deraadt 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.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;
! 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.9 deraadt 145: LOG4(sess, "remapped identifier %s: %d -> %d",
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.5 florian 158: idents_add(struct sess *sess, int isgid,
159: struct ident **ids, size_t *idsz, int32_t id)
1.1 benno 160: {
161: struct group *grp;
1.5 florian 162: struct passwd *usr;
1.1 benno 163: size_t i, sz;
164: void *pp;
1.5 florian 165: const char *name;
1.1 benno 166:
1.5 florian 167: if (id == 0)
1.3 benno 168: return 1;
169:
1.5 florian 170: for (i = 0; i < *idsz; i++)
171: if ((*ids)[i].id == id)
1.1 benno 172: return 1;
173:
1.4 benno 174: /*
1.5 florian 175: * Look up the reference in a type-specific way.
176: * Make sure that the name length is sane: we transmit it using
177: * a single byte.
1.1 benno 178: */
179:
1.5 florian 180: assert(i == *idsz);
181: if (isgid) {
182: if ((grp = getgrgid((gid_t)id)) == NULL) {
1.9 deraadt 183: ERR(sess, "%d: unknown gid", id);
1.5 florian 184: return 0;
185: }
186: name = grp->gr_name;
187: } else {
188: if ((usr = getpwuid((uid_t)id)) == NULL) {
1.9 deraadt 189: ERR(sess, "%d: unknown uid", id);
1.5 florian 190: return 0;
191: }
192: name = usr->pw_name;
193: }
194:
195: if ((sz = strlen(name)) > UINT8_MAX) {
1.9 deraadt 196: ERRX(sess, "%d: name too long: %s", id, name);
1.1 benno 197: return 0;
1.3 benno 198: } else if (sz == 0) {
1.9 deraadt 199: ERRX(sess, "%d: zero-length name", id);
1.1 benno 200: return 0;
201: }
202:
1.5 florian 203: /* Add the identifier to the array. */
1.1 benno 204:
1.5 florian 205: pp = reallocarray(*ids, *idsz + 1, sizeof(struct ident));
1.3 benno 206: if (pp == NULL) {
1.1 benno 207: ERR(sess, "reallocarray");
208: return 0;
209: }
1.5 florian 210: *ids = pp;
211: (*ids)[*idsz].id = id;
212: (*ids)[*idsz].name = strdup(name);
213: if ((*ids)[*idsz].name == NULL) {
1.1 benno 214: ERR(sess, "strdup");
215: return 0;
216: }
217:
1.5 florian 218: LOG4(sess, "adding identifier to list: %s (%u)",
1.9 deraadt 219: (*ids)[*idsz].name, (*ids)[*idsz].id);
1.5 florian 220: (*idsz)++;
1.1 benno 221: return 1;
222: }
223:
224: /*
225: * Send a list of struct ident.
226: * See idents_recv().
227: * We should only do this if we're preserving gids/uids.
228: * Return zero on failure, non-zero on success.
229: */
230: int
1.4 benno 231: idents_send(struct sess *sess,
1.1 benno 232: int fd, const struct ident *ids, size_t idsz)
233: {
234: size_t i, sz;
235:
236: for (i = 0; i < idsz; i++) {
1.3 benno 237: assert(ids[i].name != NULL);
238: assert(ids[i].id != 0);
1.1 benno 239: sz = strlen(ids[i].name);
240: assert(sz > 0 && sz <= UINT8_MAX);
1.11 ! deraadt 241: if (!io_write_uint(sess, fd, ids[i].id)) {
! 242: ERRX1(sess, "io_write_uint");
1.1 benno 243: return 0;
244: } else if (!io_write_byte(sess, fd, sz)) {
245: ERRX1(sess, "io_write_byte");
246: return 0;
247: } else if (!io_write_buf(sess, fd, ids[i].name, sz)) {
1.10 deraadt 248: ERRX1(sess, "io_write_buf");
1.1 benno 249: return 0;
250: }
251: }
252:
253: if (!io_write_int(sess, fd, 0)) {
254: ERRX1(sess, "io_write_int");
255: return 0;
256: }
257:
258: return 1;
259: }
260:
261: /*
262: * Receive a list of struct ident.
263: * See idents_send().
264: * We should only do this if we're preserving gids/uids.
265: * Return zero on failure, non-zero on success.
266: */
267: int
268: idents_recv(struct sess *sess,
269: int fd, struct ident **ids, size_t *idsz)
270: {
271: int32_t id;
272: uint8_t sz;
273: void *pp;
274:
275: for (;;) {
1.11 ! deraadt 276: if (!io_read_uint(sess, fd, &id)) {
! 277: ERRX1(sess, "io_read_uint");
1.1 benno 278: return 0;
1.3 benno 279: } else if (id == 0)
1.1 benno 280: break;
1.4 benno 281:
282: pp = reallocarray(*ids,
1.1 benno 283: *idsz + 1, sizeof(struct ident));
1.3 benno 284: if (pp == NULL) {
1.1 benno 285: ERR(sess, "reallocarray");
286: return 0;
287: }
288: *ids = pp;
289: memset(&(*ids)[*idsz], 0, sizeof(struct ident));
1.3 benno 290:
291: /*
1.5 florian 292: * When reading the size, warn if we get a size of zero.
1.3 benno 293: * The spec doesn't allow this, but we might have a
294: * noncomformant or adversarial sender.
295: */
296:
1.1 benno 297: if (!io_read_byte(sess, fd, &sz)) {
298: ERRX1(sess, "io_read_byte");
299: return 0;
1.5 florian 300: } else if (sz == 0)
1.9 deraadt 301: WARNX(sess, "zero-length name in identifier list");
1.3 benno 302:
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.1 benno 306: ERR(sess, "calloc");
307: return 0;
308: }
309: if (!io_read_buf(sess, fd, (*ids)[*idsz].name, sz)) {
310: ERRX1(sess, "io_read_buf");
311: return 0;
312: }
313: (*idsz)++;
314: }
315:
316: return 1;
317: }