static int parse_perm_line(struct identity_downcall_data *data, char *line, size_t size) { char uid_str[size]; char nid_str[size]; char perm_str[size]; lnet_nid_t nid; __u32 perm, noperm; int rc, i; if (data->idd_nperms >= N_PERMS_MAX) { errlog("permission count %d > max %d\n", data->idd_nperms, N_PERMS_MAX); return -1; } rc = sscanf(line, "%s %s %s", nid_str, uid_str, perm_str); if (rc != 3) { errlog("can't parse line %s\n", line); return -1; } if (!match_uid(data->idd_uid, uid_str)) return 0; if (!strcmp(nid_str, "*")) { nid = LNET_NID_ANY; } else { nid = libcfs_str2nid(nid_str); if (nid == LNET_NID_ANY) { errlog("can't parse nid %s\n", nid_str); return -1; } } if (parse_perm(&perm, &noperm, perm_str)) { errlog("invalid perm %s\n", perm_str); return -1; } /* merge the perms with the same nid. * * If there is LNET_NID_ANY in data->idd_perms[i].pdd_nid, * it must be data->idd_perms[0].pdd_nid, and act as default perm. */ if (nid != LNET_NID_ANY) { int found = 0; /* search for the same nid */ for (i = data->idd_nperms - 1; i >= 0; i--) { if (data->idd_perms[i].pdd_nid == nid) { data->idd_perms[i].pdd_perm = (data->idd_perms[i].pdd_perm | perm) & ~noperm; found = 1; break; } } /* NOT found, add to tail */ if (!found) { data->idd_perms[data->idd_nperms].pdd_nid = nid; data->idd_perms[data->idd_nperms].pdd_perm = perm & ~noperm; data->idd_nperms++; } } else { if (data->idd_nperms > 0) { /* the first one isn't LNET_NID_ANY, need exchange */ if (data->idd_perms[0].pdd_nid != LNET_NID_ANY) { data->idd_perms[data->idd_nperms].pdd_nid = data->idd_perms[0].pdd_nid; data->idd_perms[data->idd_nperms].pdd_perm = data->idd_perms[0].pdd_perm; data->idd_perms[0].pdd_nid = LNET_NID_ANY; data->idd_perms[0].pdd_perm = perm & ~noperm; data->idd_nperms++; } else { /* only fix LNET_NID_ANY item */ data->idd_perms[0].pdd_perm = (data->idd_perms[0].pdd_perm | perm) & ~noperm; } } else { /* it is the first one, only add to head */ data->idd_perms[0].pdd_nid = LNET_NID_ANY; data->idd_perms[0].pdd_perm = perm & ~noperm; data->idd_nperms = 1; } } return 0; }
/* recv a complete uid/gid mapping from the peer and map the uid/gid in the file list to local names */ void recv_uid_list(int f, struct file_list *flist) { int id, i; char *name; struct idlist *list; if (numeric_ids) return; if (preserve_uid) { /* read the uid list */ list = uidlist; id = read_int(f); while (id != 0) { int len = read_byte(f); name = (char *)malloc(len+1); if (!name) out_of_memory("recv_uid_list"); read_sbuf(f, name, len); if (!list) { uidlist = add_list(id, name); list = uidlist; } else { list->next = add_list(id, name); list = list->next; } list->id2 = map_uid(id, name); free(name); id = read_int(f); } } if (preserve_gid) { /* and the gid list */ list = gidlist; id = read_int(f); while (id != 0) { int len = read_byte(f); name = (char *)malloc(len+1); if (!name) out_of_memory("recv_uid_list"); read_sbuf(f, name, len); if (!list) { gidlist = add_list(id, name); list = gidlist; } else { list->next = add_list(id, name); list = list->next; } list->id2 = map_gid(id, name); free(name); id = read_int(f); } } if (!(am_root && preserve_uid) && !preserve_gid) return; /* now convert the uid/gid of all files in the list to the mapped uid/gid */ for (i=0;i<flist->count;i++) { if (am_root && preserve_uid && flist->files[i]->uid != 0) { flist->files[i]->uid = match_uid(flist->files[i]->uid); } if (preserve_gid && flist->files[i]->gid != 0) { flist->files[i]->gid = match_gid(flist->files[i]->gid); } } }