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