File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / uidlist.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Fri Feb 17 15:09:30 2012 UTC (12 years, 4 months ago) by misho
Branches: rsync, MAIN
CVS tags: rsync3_0_9p0, RSYNC3_0_9, HEAD
rsync

    1: /*
    2:  * Handle the mapping of uid/gid and user/group names between systems.
    3:  *
    4:  * Copyright (C) 1996 Andrew Tridgell
    5:  * Copyright (C) 1996 Paul Mackerras
    6:  * Copyright (C) 2004-2009 Wayne Davison
    7:  *
    8:  * This program is free software; you can redistribute it and/or modify
    9:  * it under the terms of the GNU General Public License as published by
   10:  * the Free Software Foundation; either version 3 of the License, or
   11:  * (at your option) any later version.
   12:  *
   13:  * This program is distributed in the hope that it will be useful,
   14:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   15:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16:  * GNU General Public License for more details.
   17:  *
   18:  * You should have received a copy of the GNU General Public License along
   19:  * with this program; if not, visit the http://fsf.org website.
   20:  */
   21: 
   22: /* If the source username/group does not exist on the target then use
   23:  * the numeric IDs.  Never do any mapping for uid=0 or gid=0 as these
   24:  * are special. */
   25: 
   26: #include "rsync.h"
   27: #include "io.h"
   28: 
   29: extern int verbose;
   30: extern int am_root;
   31: extern int preserve_uid;
   32: extern int preserve_gid;
   33: extern int preserve_acls;
   34: extern int numeric_ids;
   35: 
   36: #ifdef HAVE_GETGROUPS
   37: # ifndef GETGROUPS_T
   38: #  define GETGROUPS_T gid_t
   39: # endif
   40: #endif
   41: 
   42: struct idlist {
   43: 	struct idlist *next;
   44: 	const char *name;
   45: 	id_t id, id2;
   46: 	uint16 flags;
   47: };
   48: 
   49: static struct idlist *uidlist;
   50: static struct idlist *gidlist;
   51: 
   52: static struct idlist *add_to_list(struct idlist **root, id_t id, const char *name,
   53: 				  id_t id2, uint16 flags)
   54: {
   55: 	struct idlist *node = new(struct idlist);
   56: 	if (!node)
   57: 		out_of_memory("add_to_list");
   58: 	node->next = *root;
   59: 	node->name = name;
   60: 	node->id = id;
   61: 	node->id2 = id2;
   62: 	node->flags = flags;
   63: 	*root = node;
   64: 	return node;
   65: }
   66: 
   67: /* turn a uid into a user name */
   68: static const char *uid_to_name(uid_t uid)
   69: {
   70: 	struct passwd *pass = getpwuid(uid);
   71: 	if (pass)
   72: 		return strdup(pass->pw_name);
   73: 	return NULL;
   74: }
   75: 
   76: /* turn a gid into a group name */
   77: static const char *gid_to_name(gid_t gid)
   78: {
   79: 	struct group *grp = getgrgid(gid);
   80: 	if (grp)
   81: 		return strdup(grp->gr_name);
   82: 	return NULL;
   83: }
   84: 
   85: static uid_t map_uid(uid_t id, const char *name)
   86: {
   87: 	uid_t uid;
   88: 	if (id != 0 && name_to_uid(name, &uid))
   89: 		return uid;
   90: 	return id;
   91: }
   92: 
   93: static gid_t map_gid(gid_t id, const char *name)
   94: {
   95: 	gid_t gid;
   96: 	if (id != 0 && name_to_gid(name, &gid))
   97: 		return gid;
   98: 	return id;
   99: }
  100: 
  101: static int is_in_group(gid_t gid)
  102: {
  103: #ifdef HAVE_GETGROUPS
  104: 	static gid_t last_in;
  105: 	static int ngroups = -2, last_out = -1;
  106: 	static GETGROUPS_T *gidset;
  107: 	int n;
  108: 
  109: 	if (gid == last_in && last_out >= 0)
  110: 		return last_out;
  111: 	if (ngroups < -1) {
  112: 		gid_t mygid = MY_GID();
  113: 		if ((ngroups = getgroups(0, NULL)) < 0)
  114: 			ngroups = 0;
  115: 		gidset = new_array(GETGROUPS_T, ngroups+1);
  116: 		if (!gidset)
  117: 			out_of_memory("is_in_group");
  118: 		if (ngroups > 0)
  119: 			ngroups = getgroups(ngroups, gidset);
  120: 		/* The default gid might not be in the list on some systems. */
  121: 		for (n = 0; n < ngroups; n++) {
  122: 			if (gidset[n] == mygid)
  123: 				break;
  124: 		}
  125: 		if (n == ngroups)
  126: 			gidset[ngroups++] = mygid;
  127: 		if (verbose > 3) {
  128: 			int pos;
  129: 			char *gidbuf = new_array(char, ngroups*21+32);
  130: 			if (!gidbuf)
  131: 				out_of_memory("is_in_group");
  132: 			pos = snprintf(gidbuf, 32, "process has %d gid%s: ",
  133: 				       ngroups, ngroups == 1? "" : "s");
  134: 			for (n = 0; n < ngroups; n++) {
  135: 				pos += snprintf(gidbuf+pos, 21, " %d", (int)gidset[n]);
  136: 			}
  137: 			rprintf(FINFO, "%s\n", gidbuf);
  138: 			free(gidbuf);
  139: 		}
  140: 	}
  141: 
  142: 	last_in = gid;
  143: 	for (n = 0; n < ngroups; n++) {
  144: 		if (gidset[n] == gid)
  145: 			return last_out = 1;
  146: 	}
  147: 	return last_out = 0;
  148: 
  149: #else
  150: 	static gid_t mygid = GID_NONE;
  151: 	if (mygid == GID_NONE) {
  152: 		mygid = MY_GID();
  153: 		if (verbose > 3)
  154: 			rprintf(FINFO, "process has gid %u\n", (unsigned)mygid);
  155: 	}
  156: 	return gid == mygid;
  157: #endif
  158: }
  159: 
  160: /* Add a uid to the list of uids.  Only called on receiving side. */
  161: static struct idlist *recv_add_uid(uid_t id, const char *name)
  162: {
  163: 	uid_t id2 = name ? map_uid(id, name) : id;
  164: 	struct idlist *node;
  165: 
  166: 	node = add_to_list(&uidlist, id, name, id2, 0);
  167: 
  168: 	if (verbose > 3) {
  169: 		rprintf(FINFO, "uid %u(%s) maps to %u\n",
  170: 			(unsigned)id, name ? name : "", (unsigned)id2);
  171: 	}
  172: 
  173: 	return node;
  174: }
  175: 
  176: /* Add a gid to the list of gids.  Only called on receiving side. */
  177: static struct idlist *recv_add_gid(gid_t id, const char *name)
  178: {
  179: 	gid_t id2 = name ? map_gid(id, name) : id;
  180: 	struct idlist *node;
  181: 
  182: 	node = add_to_list(&gidlist, id, name, id2,
  183: 		!am_root && !is_in_group(id2) ? FLAG_SKIP_GROUP : 0);
  184: 
  185: 	if (verbose > 3) {
  186: 		rprintf(FINFO, "gid %u(%s) maps to %u\n",
  187: 			(unsigned)id, name ? name : "", (unsigned)id2);
  188: 	}
  189: 
  190: 	return node;
  191: }
  192: 
  193: /* this function is a definate candidate for a faster algorithm */
  194: uid_t match_uid(uid_t uid)
  195: {
  196: 	static uid_t last_in, last_out;
  197: 	struct idlist *list;
  198: 
  199: 	if (uid == 0)
  200: 		return 0;
  201: 
  202: 	if (uid == last_in)
  203: 		return last_out;
  204: 
  205: 	last_in = uid;
  206: 
  207: 	for (list = uidlist; list; list = list->next) {
  208: 		if (list->id == uid)
  209: 			return last_out = list->id2;
  210: 	}
  211: 
  212: 	return last_out = uid;
  213: }
  214: 
  215: gid_t match_gid(gid_t gid, uint16 *flags_ptr)
  216: {
  217: 	static struct idlist *last = NULL;
  218: 	struct idlist *list;
  219: 
  220: 	if (last && gid == last->id)
  221: 		list = last;
  222: 	else {
  223: 		for (list = gidlist; list; list = list->next) {
  224: 			if (list->id == gid)
  225: 				break;
  226: 		}
  227: 		if (!list)
  228: 			list = recv_add_gid(gid, NULL);
  229: 		last = list;
  230: 	}
  231: 
  232: 	if (flags_ptr && list->flags & FLAG_SKIP_GROUP)
  233: 		*flags_ptr |= FLAG_SKIP_GROUP;
  234: 	return list->id2;
  235: }
  236: 
  237: /* Add a uid to the list of uids.  Only called on sending side. */
  238: const char *add_uid(uid_t uid)
  239: {
  240: 	struct idlist *list;
  241: 	struct idlist *node;
  242: 
  243: 	if (uid == 0)	/* don't map root */
  244: 		return NULL;
  245: 
  246: 	for (list = uidlist; list; list = list->next) {
  247: 		if (list->id == uid)
  248: 			return NULL;
  249: 	}
  250: 
  251: 	node = add_to_list(&uidlist, uid, uid_to_name(uid), 0, 0);
  252: 	return node->name;
  253: }
  254: 
  255: /* Add a gid to the list of gids.  Only called on sending side. */
  256: const char *add_gid(gid_t gid)
  257: {
  258: 	struct idlist *list;
  259: 	struct idlist *node;
  260: 
  261: 	if (gid == 0)	/* don't map root */
  262: 		return NULL;
  263: 
  264: 	for (list = gidlist; list; list = list->next) {
  265: 		if (list->id == gid)
  266: 			return NULL;
  267: 	}
  268: 
  269: 	node = add_to_list(&gidlist, gid, gid_to_name(gid), 0, 0);
  270: 	return node->name;
  271: }
  272: 
  273: /* send a complete uid/gid mapping to the peer */
  274: void send_id_list(int f)
  275: {
  276: 	struct idlist *list;
  277: 
  278: 	if (preserve_uid || preserve_acls) {
  279: 		int len;
  280: 		/* we send sequences of uid/byte-length/name */
  281: 		for (list = uidlist; list; list = list->next) {
  282: 			if (!list->name)
  283: 				continue;
  284: 			len = strlen(list->name);
  285: 			write_varint30(f, list->id);
  286: 			write_byte(f, len);
  287: 			write_buf(f, list->name, len);
  288: 		}
  289: 
  290: 		/* terminate the uid list with a 0 uid. We explicitly exclude
  291: 		 * 0 from the list */
  292: 		write_varint30(f, 0);
  293: 	}
  294: 
  295: 	if (preserve_gid || preserve_acls) {
  296: 		int len;
  297: 		for (list = gidlist; list; list = list->next) {
  298: 			if (!list->name)
  299: 				continue;
  300: 			len = strlen(list->name);
  301: 			write_varint30(f, list->id);
  302: 			write_byte(f, len);
  303: 			write_buf(f, list->name, len);
  304: 		}
  305: 		write_varint30(f, 0);
  306: 	}
  307: }
  308: 
  309: uid_t recv_user_name(int f, uid_t uid)
  310: {
  311: 	struct idlist *node;
  312: 	int len = read_byte(f);
  313: 	char *name = new_array(char, len+1);
  314: 	if (!name)
  315: 		out_of_memory("recv_user_name");
  316: 	read_sbuf(f, name, len);
  317: 	if (numeric_ids < 0) {
  318: 		free(name);
  319: 		name = NULL;
  320: 	}
  321: 	node = recv_add_uid(uid, name); /* node keeps name's memory */
  322: 	return node->id2;
  323: }
  324: 
  325: gid_t recv_group_name(int f, gid_t gid, uint16 *flags_ptr)
  326: {
  327: 	struct idlist *node;
  328: 	int len = read_byte(f);
  329: 	char *name = new_array(char, len+1);
  330: 	if (!name)
  331: 		out_of_memory("recv_group_name");
  332: 	read_sbuf(f, name, len);
  333: 	if (numeric_ids < 0) {
  334: 		free(name);
  335: 		name = NULL;
  336: 	}
  337: 	node = recv_add_gid(gid, name); /* node keeps name's memory */
  338: 	if (flags_ptr && node->flags & FLAG_SKIP_GROUP)
  339: 		*flags_ptr |= FLAG_SKIP_GROUP;
  340: 	return node->id2;
  341: }
  342: 
  343: /* recv a complete uid/gid mapping from the peer and map the uid/gid
  344:  * in the file list to local names */
  345: void recv_id_list(int f, struct file_list *flist)
  346: {
  347: 	id_t id;
  348: 	int i;
  349: 
  350: 	if ((preserve_uid || preserve_acls) && numeric_ids <= 0) {
  351: 		/* read the uid list */
  352: 		while ((id = read_varint30(f)) != 0)
  353: 			recv_user_name(f, id);
  354: 	}
  355: 
  356: 	if ((preserve_gid || preserve_acls) && numeric_ids <= 0) {
  357: 		/* read the gid list */
  358: 		while ((id = read_varint30(f)) != 0)
  359: 			recv_group_name(f, id, NULL);
  360: 	}
  361: 
  362: 	/* Now convert all the uids/gids from sender values to our values. */
  363: #ifdef SUPPORT_ACLS
  364: 	if (preserve_acls && !numeric_ids)
  365: 		match_acl_ids();
  366: #endif
  367: 	if (am_root && preserve_uid && !numeric_ids) {
  368: 		for (i = 0; i < flist->used; i++)
  369: 			F_OWNER(flist->files[i]) = match_uid(F_OWNER(flist->files[i]));
  370: 	}
  371: 	if (preserve_gid && (!am_root || !numeric_ids)) {
  372: 		for (i = 0; i < flist->used; i++) {
  373: 			F_GROUP(flist->files[i]) = match_gid(F_GROUP(flist->files[i]),
  374: 							     &flist->files[i]->flags);
  375: 		}
  376: 	}
  377: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>