version 1.1.1.2, 2013/10/14 07:51:14
|
version 1.1.1.4, 2021/03/17 00:32:36
|
Line 3
|
Line 3
|
* |
* |
* Copyright (C) 1996 Andrew Tridgell |
* Copyright (C) 1996 Andrew Tridgell |
* Copyright (C) 1996 Paul Mackerras |
* Copyright (C) 1996 Paul Mackerras |
* Copyright (C) 2004-2013 Wayne Davison | * Copyright (C) 2004-2020 Wayne Davison |
* |
* |
* This program is free software; you can redistribute it and/or modify |
* This program is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* it under the terms of the GNU General Public License as published by |
Line 33 extern int preserve_uid;
|
Line 33 extern int preserve_uid;
|
extern int preserve_gid; |
extern int preserve_gid; |
extern int preserve_acls; |
extern int preserve_acls; |
extern int numeric_ids; |
extern int numeric_ids; |
|
extern int xmit_id0_names; |
|
extern pid_t namecvt_pid; |
extern gid_t our_gid; |
extern gid_t our_gid; |
extern char *usermap; |
extern char *usermap; |
extern char *groupmap; |
extern char *groupmap; |
Line 47 extern char *groupmap;
|
Line 49 extern char *groupmap;
|
#define NFLAGS_NAME_MATCH (1<<1) |
#define NFLAGS_NAME_MATCH (1<<1) |
|
|
union name_or_id { |
union name_or_id { |
const char *name; | const char *name; |
id_t max_id; | id_t max_id; |
}; |
}; |
|
|
struct idlist { |
struct idlist { |
Line 85 static struct idlist *add_to_list(struct idlist **root
|
Line 87 static struct idlist *add_to_list(struct idlist **root
|
id_t id2, uint16 flags) |
id_t id2, uint16 flags) |
{ |
{ |
struct idlist *node = new(struct idlist); |
struct idlist *node = new(struct idlist); |
if (!node) |
|
out_of_memory("add_to_list"); |
|
node->next = *root; |
node->next = *root; |
node->u = noiu; |
node->u = noiu; |
node->id = id; |
node->id = id; |
Line 97 static struct idlist *add_to_list(struct idlist **root
|
Line 97 static struct idlist *add_to_list(struct idlist **root
|
} |
} |
|
|
/* turn a uid into a user name */ |
/* turn a uid into a user name */ |
char *uid_to_user(uid_t uid) | const char *uid_to_user(uid_t uid) |
{ |
{ |
struct passwd *pass = getpwuid(uid); | const char *name = NULL; |
if (pass) | |
return strdup(pass->pw_name); | if (namecvt_pid) { |
return NULL; | id_t id = uid; |
| namecvt_call("uid", &name, &id); |
| } else { |
| struct passwd *pass = getpwuid(uid); |
| if (pass) |
| name = strdup(pass->pw_name); |
| } |
| |
| return name; |
} |
} |
|
|
/* turn a gid into a group name */ |
/* turn a gid into a group name */ |
char *gid_to_group(gid_t gid) | const char *gid_to_group(gid_t gid) |
{ |
{ |
struct group *grp = getgrgid(gid); | const char *name = NULL; |
if (grp) | |
return strdup(grp->gr_name); | if (namecvt_pid) { |
return NULL; | id_t id = gid; |
| namecvt_call("gid", &name, &id); |
| } else { |
| struct group *grp = getgrgid(gid); |
| if (grp) |
| name = strdup(grp->gr_name); |
| } |
| |
| return name; |
} |
} |
|
|
/* Parse a user name or (optionally) a number into a uid */ |
/* Parse a user name or (optionally) a number into a uid */ |
int user_to_uid(const char *name, uid_t *uid_p, BOOL num_ok) |
int user_to_uid(const char *name, uid_t *uid_p, BOOL num_ok) |
{ |
{ |
struct passwd *pass; |
|
if (!name || !*name) |
if (!name || !*name) |
return 0; |
return 0; |
|
|
if (num_ok && name[strspn(name, "0123456789")] == '\0') { |
if (num_ok && name[strspn(name, "0123456789")] == '\0') { |
*uid_p = id_parse(name); |
*uid_p = id_parse(name); |
return 1; |
return 1; |
} |
} |
if (!(pass = getpwnam(name))) | |
return 0; | if (namecvt_pid) { |
*uid_p = pass->pw_uid; | id_t id; |
| if (!namecvt_call("usr", &name, &id)) |
| return 0; |
| *uid_p = id; |
| } else { |
| struct passwd *pass = getpwnam(name); |
| if (!pass) |
| return 0; |
| *uid_p = pass->pw_uid; |
| } |
| |
return 1; |
return 1; |
} |
} |
|
|
/* Parse a group name or (optionally) a number into a gid */ |
/* Parse a group name or (optionally) a number into a gid */ |
int group_to_gid(const char *name, gid_t *gid_p, BOOL num_ok) |
int group_to_gid(const char *name, gid_t *gid_p, BOOL num_ok) |
{ |
{ |
struct group *grp; |
|
if (!name || !*name) |
if (!name || !*name) |
return 0; |
return 0; |
|
|
if (num_ok && name[strspn(name, "0123456789")] == '\0') { |
if (num_ok && name[strspn(name, "0123456789")] == '\0') { |
*gid_p = id_parse(name); |
*gid_p = id_parse(name); |
return 1; |
return 1; |
} |
} |
if (!(grp = getgrnam(name))) | |
return 0; | if (namecvt_pid) { |
*gid_p = grp->gr_gid; | id_t id; |
| if (!namecvt_call("grp", &name, &id)) |
| return 0; |
| *gid_p = id; |
| } else { |
| struct group *grp = getgrnam(name); |
| if (!grp) |
| return 0; |
| *gid_p = grp->gr_gid; |
| } |
| |
return 1; |
return 1; |
} |
} |
|
|
Line 160 static int is_in_group(gid_t gid)
|
Line 196 static int is_in_group(gid_t gid)
|
if ((ngroups = getgroups(0, NULL)) < 0) |
if ((ngroups = getgroups(0, NULL)) < 0) |
ngroups = 0; |
ngroups = 0; |
gidset = new_array(GETGROUPS_T, ngroups+1); |
gidset = new_array(GETGROUPS_T, ngroups+1); |
if (!gidset) |
|
out_of_memory("is_in_group"); |
|
if (ngroups > 0) |
if (ngroups > 0) |
ngroups = getgroups(ngroups, gidset); |
ngroups = getgroups(ngroups, gidset); |
/* The default gid might not be in the list on some systems. */ |
/* The default gid might not be in the list on some systems. */ |
Line 174 static int is_in_group(gid_t gid)
|
Line 208 static int is_in_group(gid_t gid)
|
if (DEBUG_GTE(OWN, 2)) { |
if (DEBUG_GTE(OWN, 2)) { |
int pos; |
int pos; |
char *gidbuf = new_array(char, ngroups*21+32); |
char *gidbuf = new_array(char, ngroups*21+32); |
if (!gidbuf) | pos = snprintf(gidbuf, 32, "process has %d gid%s: ", ngroups, ngroups == 1? "" : "s"); |
out_of_memory("is_in_group"); | |
pos = snprintf(gidbuf, 32, "process has %d gid%s: ", | |
ngroups, ngroups == 1? "" : "s"); | |
for (n = 0; n < ngroups; n++) { |
for (n = 0; n < ngroups; n++) { |
pos += snprintf(gidbuf+pos, 21, " %d", (int)gidset[n]); |
pos += snprintf(gidbuf+pos, 21, " %d", (int)gidset[n]); |
} |
} |
Line 252 static struct idlist *recv_add_id(struct idlist **idli
|
Line 283 static struct idlist *recv_add_id(struct idlist **idli
|
return node; |
return node; |
} |
} |
|
|
/* this function is a definate candidate for a faster algorithm */ | /* this function is a definite candidate for a faster algorithm */ |
uid_t match_uid(uid_t uid) |
uid_t match_uid(uid_t uid) |
{ |
{ |
static struct idlist *last = NULL; |
static struct idlist *last = NULL; |
Line 302 const char *add_uid(uid_t uid)
|
Line 333 const char *add_uid(uid_t uid)
|
struct idlist *node; |
struct idlist *node; |
union name_or_id noiu; |
union name_or_id noiu; |
|
|
if (uid == 0) /* don't map root */ |
|
return NULL; |
|
|
|
for (list = uidlist; list; list = list->next) { |
for (list = uidlist; list; list = list->next) { |
if (list->id == uid) |
if (list->id == uid) |
return NULL; |
return NULL; |
Line 322 const char *add_gid(gid_t gid)
|
Line 350 const char *add_gid(gid_t gid)
|
struct idlist *node; |
struct idlist *node; |
union name_or_id noiu; |
union name_or_id noiu; |
|
|
if (gid == 0) /* don't map root */ |
|
return NULL; |
|
|
|
for (list = gidlist; list; list = list->next) { |
for (list = gidlist; list; list = list->next) { |
if (list->id == gid) |
if (list->id == gid) |
return NULL; |
return NULL; |
Line 335 const char *add_gid(gid_t gid)
|
Line 360 const char *add_gid(gid_t gid)
|
return node->u.name; |
return node->u.name; |
} |
} |
|
|
/* send a complete uid/gid mapping to the peer */ | static void send_one_name(int f, id_t id, const char *name) |
void send_id_list(int f) | |
{ |
{ |
struct idlist *list; | int len; |
|
|
if (preserve_uid || preserve_acls) { | if (!name) |
int len; | name = ""; |
/* we send sequences of uid/byte-length/name */ | if ((len = strlen(name)) > 255) /* Impossible? */ |
for (list = uidlist; list; list = list->next) { | len = 255; |
if (!list->u.name) | |
continue; | |
len = strlen(list->u.name); | |
write_varint30(f, list->id); | |
write_byte(f, len); | |
write_buf(f, list->u.name, len); | |
} | |
|
|
/* terminate the uid list with a 0 uid. We explicitly exclude | write_varint30(f, id); |
* 0 from the list */ | write_byte(f, len); |
write_varint30(f, 0); | if (len) |
| write_buf(f, name, len); |
| } |
| |
| static void send_one_list(int f, struct idlist *idlist, int usernames) |
| { |
| struct idlist *list; |
| |
| /* we send sequences of id/byte-len/name */ |
| for (list = idlist; list; list = list->next) { |
| if (list->id && list->u.name) |
| send_one_name(f, list->id, list->u.name); |
} |
} |
|
|
if (preserve_gid || preserve_acls) { | /* Terminate the uid list with 0 (which was excluded above). |
int len; | * A modern rsync also sends the name of id 0. */ |
for (list = gidlist; list; list = list->next) { | if (xmit_id0_names) |
if (!list->u.name) | send_one_name(f, 0, usernames ? uid_to_user(0) : gid_to_group(0)); |
continue; | else |
len = strlen(list->u.name); | |
write_varint30(f, list->id); | |
write_byte(f, len); | |
write_buf(f, list->u.name, len); | |
} | |
write_varint30(f, 0); |
write_varint30(f, 0); |
} |
|
} |
} |
|
|
|
/* send a complete uid/gid mapping to the peer */ |
|
void send_id_lists(int f) |
|
{ |
|
if (preserve_uid || preserve_acls) |
|
send_one_list(f, uidlist, 1); |
|
|
|
if (preserve_gid || preserve_acls) |
|
send_one_list(f, gidlist, 0); |
|
} |
|
|
uid_t recv_user_name(int f, uid_t uid) |
uid_t recv_user_name(int f, uid_t uid) |
{ |
{ |
struct idlist *node; |
struct idlist *node; |
int len = read_byte(f); |
int len = read_byte(f); |
char *name = new_array(char, len+1); | char *name; |
if (!name) | |
out_of_memory("recv_user_name"); | if (len) { |
read_sbuf(f, name, len); | name = new_array(char, len+1); |
if (numeric_ids < 0) { | read_sbuf(f, name, len); |
free(name); | if (numeric_ids < 0) { |
| free(name); |
| name = NULL; |
| } |
| } else |
name = NULL; |
name = NULL; |
} | |
node = recv_add_id(&uidlist, uidmap, uid, name); /* node keeps name's memory */ |
node = recv_add_id(&uidlist, uidmap, uid, name); /* node keeps name's memory */ |
return node->id2; |
return node->id2; |
} |
} |
Line 391 gid_t recv_group_name(int f, gid_t gid, uint16 *flags_
|
Line 427 gid_t recv_group_name(int f, gid_t gid, uint16 *flags_
|
{ |
{ |
struct idlist *node; |
struct idlist *node; |
int len = read_byte(f); |
int len = read_byte(f); |
char *name = new_array(char, len+1); | char *name; |
if (!name) | |
out_of_memory("recv_group_name"); | if (len) { |
read_sbuf(f, name, len); | name = new_array(char, len+1); |
if (numeric_ids < 0) { | read_sbuf(f, name, len); |
free(name); | if (numeric_ids < 0) { |
| free(name); |
| name = NULL; |
| } |
| } else |
name = NULL; |
name = NULL; |
} | |
node = recv_add_id(&gidlist, gidmap, gid, name); /* node keeps name's memory */ |
node = recv_add_id(&gidlist, gidmap, gid, name); /* node keeps name's memory */ |
if (flags_ptr && node->flags & FLAG_SKIP_GROUP) |
if (flags_ptr && node->flags & FLAG_SKIP_GROUP) |
*flags_ptr |= FLAG_SKIP_GROUP; |
*flags_ptr |= FLAG_SKIP_GROUP; |
Line 416 void recv_id_list(int f, struct file_list *flist)
|
Line 456 void recv_id_list(int f, struct file_list *flist)
|
/* read the uid list */ |
/* read the uid list */ |
while ((id = read_varint30(f)) != 0) |
while ((id = read_varint30(f)) != 0) |
recv_user_name(f, id); |
recv_user_name(f, id); |
|
if (xmit_id0_names) |
|
recv_user_name(f, 0); |
} |
} |
|
|
if ((preserve_gid || preserve_acls) && numeric_ids <= 0) { |
if ((preserve_gid || preserve_acls) && numeric_ids <= 0) { |
/* read the gid list */ |
/* read the gid list */ |
while ((id = read_varint30(f)) != 0) |
while ((id = read_varint30(f)) != 0) |
recv_group_name(f, id, NULL); |
recv_group_name(f, id, NULL); |
|
if (xmit_id0_names) |
|
recv_group_name(f, 0, NULL); |
} |
} |
|
|
/* Now convert all the uids/gids from sender values to our values. */ |
/* Now convert all the uids/gids from sender values to our values. */ |
Line 435 void recv_id_list(int f, struct file_list *flist)
|
Line 479 void recv_id_list(int f, struct file_list *flist)
|
} |
} |
if (preserve_gid && (!am_root || !numeric_ids || groupmap)) { |
if (preserve_gid && (!am_root || !numeric_ids || groupmap)) { |
for (i = 0; i < flist->used; i++) { |
for (i = 0; i < flist->used; i++) { |
F_GROUP(flist->files[i]) = match_gid(F_GROUP(flist->files[i]), | F_GROUP(flist->files[i]) = match_gid(F_GROUP(flist->files[i]), &flist->files[i]->flags); |
&flist->files[i]->flags); | |
} |
} |
} |
} |
} |
} |
Line 473 void parse_name_map(char *map, BOOL usernames)
|
Line 516 void parse_name_map(char *map, BOOL usernames)
|
usernames ? "user" : "group", cp); |
usernames ? "user" : "group", cp); |
exit_cleanup(RERR_SYNTAX); |
exit_cleanup(RERR_SYNTAX); |
} |
} |
if (dash) | if (dash) { |
| *dash = '\0'; |
noiu.max_id = id_parse(dash+1); |
noiu.max_id = id_parse(dash+1); |
else | } else |
noiu.max_id = 0; |
noiu.max_id = 0; |
flags = 0; |
flags = 0; |
id1 = id_parse(cp); |
id1 = id_parse(cp); |
|
if (dash) |
|
*dash = '-'; |
} else if (strpbrk(cp, "*[?")) { |
} else if (strpbrk(cp, "*[?")) { |
flags = NFLAGS_WILD_NAME_MATCH; |
flags = NFLAGS_WILD_NAME_MATCH; |
noiu.name = cp; |
noiu.name = cp; |
Line 494 void parse_name_map(char *map, BOOL usernames)
|
Line 540 void parse_name_map(char *map, BOOL usernames)
|
if (user_to_uid(colon+1, &uid, True)) |
if (user_to_uid(colon+1, &uid, True)) |
add_to_list(idmap_ptr, id1, noiu, uid, flags); |
add_to_list(idmap_ptr, id1, noiu, uid, flags); |
else { |
else { |
rprintf(FERROR, | rprintf(FERROR, "Unknown --usermap name on receiver: %s\n", colon+1); |
"Unknown --usermap name on receiver: %s\n", | |
colon+1); | |
} |
} |
} else { |
} else { |
gid_t gid; |
gid_t gid; |
if (group_to_gid(colon+1, &gid, True)) |
if (group_to_gid(colon+1, &gid, True)) |
add_to_list(idmap_ptr, id1, noiu, gid, flags); |
add_to_list(idmap_ptr, id1, noiu, gid, flags); |
else { |
else { |
rprintf(FERROR, | rprintf(FERROR, "Unknown --groupmap name on receiver: %s\n", colon+1); |
"Unknown --groupmap name on receiver: %s\n", | |
colon+1); | |
} |
} |
} |
} |
|
|
Line 515 void parse_name_map(char *map, BOOL usernames)
|
Line 557 void parse_name_map(char *map, BOOL usernames)
|
*--cp = '\0'; /* replace comma */ |
*--cp = '\0'; /* replace comma */ |
} |
} |
|
|
/* The 0 user/group doesn't get its name sent, so add it explicitly. */ | /* If the sender isn't going to xmit the id0 name, we assume it's "root". */ |
recv_add_id(idlist_ptr, *idmap_ptr, 0, | if (!xmit_id0_names) |
numeric_ids ? NULL : usernames ? uid_to_user(0) : gid_to_group(0)); | recv_add_id(idlist_ptr, *idmap_ptr, 0, numeric_ids ? NULL : "root"); |
} |
} |
|
|
#ifdef HAVE_GETGROUPLIST |
#ifdef HAVE_GETGROUPLIST |
const char *getallgroups(uid_t uid, gid_t *gid_list, int *size_ptr) | const char *getallgroups(uid_t uid, item_list *gid_list) |
{ |
{ |
struct passwd *pw; |
struct passwd *pw; |
|
gid_t *gid_array; |
|
int size; |
|
|
if ((pw = getpwuid(uid)) == NULL) |
if ((pw = getpwuid(uid)) == NULL) |
return "getpwuid failed"; |
return "getpwuid failed"; |
|
|
|
gid_list->count = 0; /* We're overwriting any items in the list */ |
|
(void)EXPAND_ITEM_LIST(gid_list, gid_t, 32); |
|
size = gid_list->malloced; |
|
|
/* Get all the process's groups, with the pw_gid group first. */ |
/* Get all the process's groups, with the pw_gid group first. */ |
if (getgrouplist(pw->pw_name, pw->pw_gid, gid_list, size_ptr) < 0) | if (getgrouplist(pw->pw_name, pw->pw_gid, gid_list->items, &size) < 0) { |
return "getgrouplist failed"; | if (size > (int)gid_list->malloced) { |
| gid_list->count = gid_list->malloced; |
| (void)EXPAND_ITEM_LIST(gid_list, gid_t, size); |
| if (getgrouplist(pw->pw_name, pw->pw_gid, gid_list->items, &size) < 0) |
| size = -1; |
| } else |
| size = -1; |
| if (size < 0) |
| return "getgrouplist failed"; |
| } |
| gid_list->count = size; |
| gid_array = gid_list->items; |
| |
/* Paranoia: is the default group not first in the list? */ |
/* Paranoia: is the default group not first in the list? */ |
if (gid_list[0] != pw->pw_gid) { | if (gid_array[0] != pw->pw_gid) { |
int j; |
int j; |
for (j = 0; j < *size_ptr; j++) { | for (j = 1; j < size; j++) { |
if (gid_list[j] == pw->pw_gid) { | if (gid_array[j] == pw->pw_gid) |
gid_list[j] = gid_list[0]; | |
gid_list[0] = pw->pw_gid; | |
break; |
break; |
} |
|
} |
} |
|
if (j == size) { /* The default group wasn't found! */ |
|
(void)EXPAND_ITEM_LIST(gid_list, gid_t, size+1); |
|
gid_array = gid_list->items; |
|
} |
|
gid_array[j] = gid_array[0]; |
|
gid_array[0] = pw->pw_gid; |
} |
} |
|
|
return NULL; |
return NULL; |
} |
} |
#endif |
#endif |