Skip to content

Commit

Permalink
extdom: plugin doesn't allow @ in group name
Browse files Browse the repository at this point in the history
Old implementation handles username and group names with
one common call. Character @ is used in the call to detect UPN.

Group name can legaly contain this character and therefore the
common approach doesn't work in such case.

Also the original call is less efficient because it tries to resolv
username allways then it fallback to group resolution.

Here we implement two new separate calls for resolving users and
groups.

Fixes: https://bugzilla.redhat.com/1746951
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
  • Loading branch information
thalman authored and abbra committed Sep 12, 2019
1 parent a8703cd commit 51723c7
Show file tree
Hide file tree
Showing 3 changed files with 197 additions and 85 deletions.
8 changes: 6 additions & 2 deletions daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@

#define EXOP_EXTDOM_OID "2.16.840.1.113730.3.8.10.4"
#define EXOP_EXTDOM_V1_OID "2.16.840.1.113730.3.8.10.4.1"
#define EXOP_EXTDOM_V2_OID "2.16.840.1.113730.3.8.10.4.2"

#define IPA_EXTDOM_PLUGIN_NAME "ipa-extdom-extop"
#define IPA_EXTDOM_FEATURE_DESC "IPA trusted domain ID mapper"
Expand All @@ -72,15 +73,18 @@

enum extdom_version {
EXTDOM_V0 = 0,
EXTDOM_V1
EXTDOM_V1,
EXTDOM_V2
};

enum input_types {
INP_SID = 1,
INP_NAME,
INP_POSIX_UID,
INP_POSIX_GID,
INP_CERT
INP_CERT,
INP_USERNAME,
INP_GROUPNAME
};

enum request_types {
Expand Down
271 changes: 188 additions & 83 deletions daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,9 @@ int parse_request_data(struct berval *req_val, struct extdom_req **_req)
* sid (1),
* name (2),
* posix uid (3),
* posix gid (3)
* posix gid (4),
* username (5),
* groupname (6)
* },
* requestType ENUMERATED {
* simple (1),
Expand Down Expand Up @@ -337,6 +339,8 @@ int parse_request_data(struct berval *req_val, struct extdom_req **_req)

switch (req->input_type) {
case INP_NAME:
case INP_USERNAME:
case INP_GROUPNAME:
tag = ber_scanf(ber, "{aa}}", &req->data.name.domain_name,
&req->data.name.object_name);
break;
Expand Down Expand Up @@ -378,6 +382,8 @@ void free_req_data(struct extdom_req *req)

switch (req->input_type) {
case INP_NAME:
case INP_USERNAME:
case INP_GROUPNAME:
ber_memfree(req->data.name.domain_name);
ber_memfree(req->data.name.object_name);
break;
Expand Down Expand Up @@ -407,6 +413,12 @@ int check_request(struct extdom_req *req, enum extdom_version version)
}
}

if (version == EXTDOM_V0 || version == EXTDOM_V1) {
if (req->input_type == INP_USERNAME || req->input_type == INP_GROUPNAME) {
return LDAP_PROTOCOL_ERROR;
}
}

return LDAP_SUCCESS;
}

Expand Down Expand Up @@ -1157,17 +1169,46 @@ static int handle_sid_request(struct ipa_extdom_ctx *ctx,
return ret;
}

static int handle_name_request(struct ipa_extdom_ctx *ctx,
struct extdom_req *req,
enum request_types request_type,
const char *name, const char *domain_name,
struct berval **berval)

static int handle_simple_request(struct extdom_req *req,
const char *fq_name,
struct berval **berval)
{
int ret;
char *sid_str = NULL;
enum sss_id_type id_type;

ret = sss_nss_getsidbyname(fq_name, &sid_str, &id_type);
switch(ret) {
case 0:
ret = pack_ber_sid(sid_str, berval);
break;
case ENOENT:
ret = LDAP_NO_SUCH_OBJECT;
break;
case ETIMEDOUT:
case ETIME:
ret = LDAP_TIMELIMIT_EXCEEDED;
break;
default:
set_err_msg(req, "Failed to lookup SID by name");
ret = LDAP_OPERATIONS_ERROR;
break;
}

free(sid_str);
return ret;
}

static int handle_username_request(struct ipa_extdom_ctx *ctx,
struct extdom_req *req,
enum request_types request_type,
const char *name, const char *domain_name,
struct berval **berval)
{
int ret;
char *fq_name = NULL;
struct passwd pwd;
struct group grp;
char *sid_str = NULL;
enum sss_id_type id_type;
size_t buf_len;
char *buf = NULL;
Expand All @@ -1189,104 +1230,156 @@ static int handle_name_request(struct ipa_extdom_ctx *ctx,
}

if (request_type == REQ_SIMPLE) {
ret = sss_nss_getsidbyname(fq_name, &sid_str, &id_type);
if (ret != 0) {
if (ret == ENOENT) {
ret = LDAP_NO_SUCH_OBJECT;
} else if (ret == ETIMEDOUT || ret == ETIME) {
ret = LDAP_TIMELIMIT_EXCEEDED;
} else {
set_err_msg(req, "Failed to lookup SID by name");
ret = LDAP_OPERATIONS_ERROR;
}
goto done;
}
/* REQ_SIMPLE */
ret = handle_simple_request(req, fq_name, berval);
goto done;
}

ret = pack_ber_sid(sid_str, berval);
} else {
ret = get_buffer(&buf_len, &buf);
if (ret != LDAP_SUCCESS) {
goto done;
}
/* REQ_FULL || REQ_FULL_WITH_GROUPS */
ret = get_buffer(&buf_len, &buf);
if (ret != LDAP_SUCCESS) {
goto done;
}

ret = getpwnam_r_wrapper(ctx, fq_name, &pwd, &buf, &buf_len);
if (ret == 0) {
if (request_type == REQ_FULL_WITH_GROUPS) {
ret = sss_nss_getorigbyname(pwd.pw_name, &kv_list, &id_type);
if (ret != 0 || !(id_type == SSS_ID_TYPE_UID
|| id_type == SSS_ID_TYPE_BOTH)) {
set_err_msg(req, "Failed to read original data");
if (ret == ENOENT) {
ret = LDAP_NO_SUCH_OBJECT;
} else if (ret == ETIMEDOUT || ret == ETIME) {
ret = LDAP_TIMELIMIT_EXCEEDED;
} else {
ret = LDAP_OPERATIONS_ERROR;
}
goto done;
}
}
ret = pack_ber_user(ctx,
(request_type == REQ_FULL ? RESP_USER
: RESP_USER_GROUPLIST),
domain_name, pwd.pw_name, pwd.pw_uid,
pwd.pw_gid, pwd.pw_gecos, pwd.pw_dir,
pwd.pw_shell, kv_list, berval);
} else if (ret == ENOMEM || ret == ERANGE) {
ret = LDAP_OPERATIONS_ERROR;
goto done;
} else if (ret == ETIMEDOUT) {
ret = LDAP_TIMELIMIT_EXCEEDED;
goto done;
} else { /* no user entry found */
/* according to the getpwnam() man page there are a couple of
* error codes which can indicate that the user was not found. To
* be on the safe side we fail back to the group lookup on all
* errors. */
ret = getgrnam_r_wrapper(ctx, fq_name, &grp, &buf, &buf_len);
if (ret != 0) {
ret = getpwnam_r_wrapper(ctx, fq_name, &pwd, &buf, &buf_len);
switch(ret) {
case 0:
if (request_type == REQ_FULL_WITH_GROUPS) {
ret = sss_nss_getorigbyname(pwd.pw_name, &kv_list, &id_type);
if (ret != 0 || !(id_type == SSS_ID_TYPE_UID
|| id_type == SSS_ID_TYPE_BOTH)) {
set_err_msg(req, "Failed to read original data");
if (ret == ENOENT) {
ret = LDAP_NO_SUCH_OBJECT;
} else if (ret == ETIMEDOUT) {
} else if (ret == ETIMEDOUT || ret == ETIME) {
ret = LDAP_TIMELIMIT_EXCEEDED;
} else {
ret = LDAP_OPERATIONS_ERROR;
}
goto done;
}
}
ret = pack_ber_user(ctx,
(request_type == REQ_FULL ? RESP_USER
: RESP_USER_GROUPLIST),
domain_name, pwd.pw_name, pwd.pw_uid,
pwd.pw_gid, pwd.pw_gecos, pwd.pw_dir,
pwd.pw_shell, kv_list, berval);
break;
case ENOMEM:
case ERANGE:
ret = LDAP_OPERATIONS_ERROR;
break;
case ETIMEDOUT:
ret = LDAP_TIMELIMIT_EXCEEDED;
break;
default:
ret = LDAP_NO_SUCH_OBJECT;
break;
}

if (request_type == REQ_FULL_WITH_GROUPS) {
ret = sss_nss_getorigbyname(grp.gr_name, &kv_list, &id_type);
if (ret != 0 || !(id_type == SSS_ID_TYPE_GID
|| id_type == SSS_ID_TYPE_BOTH)) {
if (ret == ENOENT) {
ret = LDAP_NO_SUCH_OBJECT;
} else if (ret == ETIMEDOUT || ret == ETIME) {
ret = LDAP_TIMELIMIT_EXCEEDED;
} else {
set_err_msg(req, "Failed to read original data");
ret = LDAP_OPERATIONS_ERROR;
}
goto done;
}
}
done:
sss_nss_free_kv(kv_list);
free(fq_name);
free(buf);

return ret;
}

ret = pack_ber_group((request_type == REQ_FULL ? RESP_GROUP
: RESP_GROUP_MEMBERS),
domain_name, grp.gr_name, grp.gr_gid,
grp.gr_mem, kv_list, berval);
static int handle_groupname_request(struct ipa_extdom_ctx *ctx,
struct extdom_req *req,
enum request_types request_type,
const char *name, const char *domain_name,
struct berval **berval)
{
int ret;
char *fq_name = NULL;
struct group grp;
enum sss_id_type id_type;
size_t buf_len;
char *buf = NULL;
struct sss_nss_kv *kv_list = NULL;

/* with groups we can be sure that name doesn't contain the domain_name */
ret = asprintf(&fq_name, "%s%c%s", name, SSSD_DOMAIN_SEPARATOR,
domain_name);
if (ret == -1) {
ret = LDAP_OPERATIONS_ERROR;
set_err_msg(req, "Failed to create fully qualified name");
fq_name = NULL; /* content is undefined according to
asprintf(3) */
goto done;
}

if (request_type == REQ_SIMPLE) {
/* REQ_SIMPLE */
ret = handle_simple_request(req, fq_name, berval);
goto done;
}

/* REQ_FULL || REQ_FULL_WITH_GROUPS */
ret = get_buffer(&buf_len, &buf);
if (ret != LDAP_SUCCESS) {
goto done;
}

ret = getgrnam_r_wrapper(ctx, fq_name, &grp, &buf, &buf_len);
if (ret != 0) {
if (ret == ENOMEM || ret == ERANGE) {
ret = LDAP_OPERATIONS_ERROR;
} else {
ret = LDAP_NO_SUCH_OBJECT;
}
goto done;
}

if (request_type == REQ_FULL_WITH_GROUPS) {
ret = sss_nss_getorigbyname(grp.gr_name, &kv_list, &id_type);
if (ret != 0 || !(id_type == SSS_ID_TYPE_GID
|| id_type == SSS_ID_TYPE_BOTH)) {
if (ret == ENOENT) {
ret = LDAP_NO_SUCH_OBJECT;
} else {
set_err_msg(req, "Failed to read original data");
ret = LDAP_OPERATIONS_ERROR;
}
goto done;
}
}

ret = pack_ber_group((request_type == REQ_FULL ? RESP_GROUP
: RESP_GROUP_MEMBERS),
domain_name, grp.gr_name, grp.gr_gid,
grp.gr_mem, kv_list, berval);

done:
sss_nss_free_kv(kv_list);
free(fq_name);
free(sid_str);
free(buf);

return ret;
}

static int handle_name_request(struct ipa_extdom_ctx *ctx,
struct extdom_req *req,
enum request_types request_type,
const char *name, const char *domain_name,
struct berval **berval)
{
int ret;


ret = handle_username_request(ctx, req, request_type,
name, domain_name, berval);
if (ret == LDAP_NO_SUCH_OBJECT) {
ret = handle_groupname_request(ctx, req, request_type,
name, domain_name, berval);
}

return ret;
}


int handle_request(struct ipa_extdom_ctx *ctx, struct extdom_req *req,
struct berval **berval)
{
Expand Down Expand Up @@ -1318,6 +1411,18 @@ int handle_request(struct ipa_extdom_ctx *ctx, struct extdom_req *req,
req->data.name.object_name,
req->data.name.domain_name, berval);

break;
case INP_GROUPNAME:
ret = handle_groupname_request(ctx, req, req->request_type,
req->data.name.object_name,
req->data.name.domain_name, berval);

break;
case INP_USERNAME:
ret = handle_username_request(ctx, req, req->request_type,
req->data.name.object_name,
req->data.name.domain_name, berval);

break;
default:
set_err_msg(req, "Unknown input type");
Expand Down
3 changes: 3 additions & 0 deletions daemons/ipa-slapi-plugins/ipa-extdom-extop/ipa_extdom_extop.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ Slapi_PluginDesc ipa_extdom_plugin_desc = {
static char *ipa_extdom_oid_list[] = {
EXOP_EXTDOM_OID,
EXOP_EXTDOM_V1_OID,
EXOP_EXTDOM_V2_OID,
NULL
};

Expand Down Expand Up @@ -196,6 +197,8 @@ static int ipa_extdom_extop(Slapi_PBlock *pb)
version = EXTDOM_V0;
} else if (strcasecmp(oid, EXOP_EXTDOM_V1_OID) == 0) {
version = EXTDOM_V1;
} else if (strcasecmp(oid, EXOP_EXTDOM_V2_OID) == 0) {
version = EXTDOM_V2;
} else {
return SLAPI_PLUGIN_EXTENDED_NOT_HANDLED;
}
Expand Down

0 comments on commit 51723c7

Please sign in to comment.