#ifdef HAVE_CONFIG_H #include "../config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include "nis.h" #include "plugin.h" #include "schema.h" #define DUMMY_KEY "leeroy" #define DUMMY_VAL "jimbo:*K*:1234:5678:Leeroy Jenkins:/home/leeroy:/bin/bash" /* send a reply which _could_ be sent over a datagram */ static void nis_reply_fragment(int client, struct sockaddr *client_addr, socklen_t client_addrlen, struct rpc_msg *reply, XDR *reply_xdrs, char *reply_buf, bool_t first_fragment, bool_t last_fragment) { uint32_t len; struct iovec iov[2]; ssize_t i; if (client_addr != NULL) { /* datagram reply */ xdr_replymsg(reply_xdrs, reply); slapi_log_error(SLAPI_LOG_PLUGIN, "blah", "datagram reply (%d bytes)\n", xdr_getpos(reply_xdrs)); sendto(client, reply_buf, xdr_getpos(reply_xdrs), 0, client_addr, client_addrlen); } else { /* record reply - one fragment */ if (first_fragment) { xdr_replymsg(reply_xdrs, reply); } /* calculate the fragment length bytes */ len = htonl(xdr_getpos(reply_xdrs) | (last_fragment ? 0x80000000 : 0)); slapi_log_error(SLAPI_LOG_PLUGIN, "blah", "stream reply (4+%d bytes)\n", xdr_getpos(reply_xdrs)); iov[0].iov_base = &len; iov[0].iov_len = 4; iov[1].iov_base = reply_buf; iov[1].iov_len = xdr_getpos(reply_xdrs); i = writev(client, iov, 2); if (i != (4 + xdr_getpos(reply_xdrs))) { slapi_log_error(SLAPI_LOG_PLUGIN, "blah", "error sending stream reply\n"); } } } /* send an entire reply datagram or record */ static void nis_reply(int client, struct sockaddr *client_addr, socklen_t client_addrlen, struct rpc_msg *reply, XDR *reply_xdrs, char *reply_buf) { nis_reply_fragment(client, client_addr, client_addrlen, reply, reply_xdrs, reply_buf, TRUE, TRUE); } /* indicate whether or not we support a specified domain */ static void nis_domain(struct plugin_state *state, int client, struct sockaddr *client_addr, socklen_t client_addrlen, XDR *request_xdrs, bool_t reply_on_failure, struct rpc_msg *reply, XDR *reply_xdrs, char *reply_buf, bool_t *reply_bool) { char *domain; *reply_bool = FALSE; if (xdr_string(request_xdrs, &domain, YPMAXDOMAIN)) { *reply_bool = schema_supports_domain(domain); if (*reply_bool || reply_on_failure) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "domain(%s) -> %d\n", domain, *reply_bool); nis_reply(client, client_addr, client_addrlen, reply, reply_xdrs, reply_buf); } else { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "domain(%s) -> %d (no reply)\n", domain, *reply_bool); } } else { /* XXX */ } } struct nis_match_data { struct plugin_state *state; const char *format; int result; char value[YPMAXRECORD]; }; static void nis_match_cb_result(int rc, void *callback_data) { struct nis_match_data *data = callback_data; data->result = rc; } static int nis_match_cb_entry(Slapi_Entry *e, void *callback_data) { struct nis_match_data *data = callback_data; Slapi_Attr *attr; Slapi_ValueSet *values; Slapi_Value *value; const char *dn; const struct berval *val; int i; if (strlen(data->value) == 0) { dn = slapi_entry_get_dn(e); if (strlen(dn) < sizeof(data->value)) { strcpy(data->value, dn); data->result = YP_TRUE; } } #if 0 attr = NULL; if (slapi_entry_attr_find(e, "ou", &attr) == 0) { values = NULL; if (slapi_attr_get_valueset(attr, &values) == 0) { i = slapi_valueset_first_value(values, &value); while (i != -1) { val = slapi_value_get_berval(value); if (val != NULL) { write(data->client, val->bv_val, val->bv_len); write(data->client, "\n", 1); } i = slapi_valueset_next_value(values, i, &value); } } } #endif return 0; } static int nis_match_cb_referral(char *referral, void *callback_data) { /* no referral chasing for us */ return 0; } static void nis_match(struct plugin_state *state, int client, struct sockaddr *client_addr, socklen_t client_addrlen, XDR *request_xdrs, struct rpc_msg *reply, XDR *reply_xdrs, char *reply_buf, struct ypresp_val *reply_val) { Slapi_PBlock *pblock; struct nis_match_data match_data; char *base, *key, *format, **attrs = NULL; int scope, i; struct ypreq_key req_key; memset(&req_key, 0, sizeof(req_key)); if (xdr_ypreq_key(request_xdrs, &req_key)) { /* we'll emulate an anonymous search */ pblock = slapi_pblock_new(); slapi_pblock_set(pblock, SLAPI_CONN_DN, ""); slapi_pblock_set(pblock, SLAPI_CONN_AUTHMETHOD, SLAPD_AUTH_NONE); /* set up callback data so that we can construct an answer */ memset(&match_data, 0, sizeof(match_data)); match_data.state = state; match_data.result = LDAP_NO_SUCH_OBJECT; /* set search parameters */ slapi_search_internal_set_pb(pblock, "dc=boston,dc=redhat,dc=com", LDAP_SCOPE_ONE, "(objectclass=*)", attrs, 0, NULL, NULL, state->plugin_identity, 0); /* execute the search */ i = slapi_search_internal_callback_pb(pblock, &match_data, nis_match_cb_result, nis_match_cb_entry, nis_match_cb_referral); slapi_pblock_destroy(pblock); if ((match_data.result == 0) && (strlen(match_data.value) > 0)) { reply_val->status = YP_TRUE; reply_val->valdat.valdat_val = match_data.value; reply_val->valdat.valdat_len = strlen(match_data.value); slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "match(%s/%s/%.*s) -> %d\n", req_key.domain, req_key.map, (int) req_key.keydat.keydat_len, req_key.keydat.keydat_val, reply_val->status); } else { reply_val->status = YP_NOKEY; } nis_reply(client, client_addr, client_addrlen, reply, reply_xdrs, reply_buf); } else { /* XXX */ } } static void nis_first(struct plugin_state *state, int client, struct sockaddr *client_addr, socklen_t client_addrlen, XDR *request_xdrs, struct rpc_msg *reply, XDR *reply_xdrs, char *reply_buf, struct ypresp_key_val *reply_key_val) { struct ypreq_nokey req_nokey; memset(&req_nokey, 0, sizeof(req_nokey)); if (xdr_ypreq_nokey(request_xdrs, &req_nokey)) { reply_key_val->status = YP_TRUE; reply_key_val->keydat.keydat_val = DUMMY_KEY; reply_key_val->keydat.keydat_len = strlen(DUMMY_KEY); reply_key_val->valdat.valdat_val = DUMMY_VAL; reply_key_val->valdat.valdat_len = strlen(DUMMY_VAL); slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "first(%s/%s) -> %d\n", req_nokey.domain, req_nokey.map, reply_key_val->status); nis_reply(client, client_addr, client_addrlen, reply, reply_xdrs, reply_buf); } else { /* XXX */ } } static void nis_next(struct plugin_state *state, int client, struct sockaddr *client_addr, socklen_t client_addrlen, XDR *request_xdrs, struct rpc_msg *reply, XDR *reply_xdrs, char *reply_buf, struct ypresp_key_val *reply_key_val) { struct ypreq_key req_key; memset(&req_key, 0, sizeof(req_key)); if (xdr_ypreq_key(request_xdrs, &req_key)) { if (time(NULL) % 2) { reply_key_val->status = YP_TRUE; reply_key_val->keydat.keydat_val = DUMMY_KEY; reply_key_val->keydat.keydat_len = strlen(DUMMY_KEY); reply_key_val->valdat.valdat_val = DUMMY_VAL; reply_key_val->valdat.valdat_len = strlen(DUMMY_VAL); slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "next(%s/%s/%.*s) -> %d\n", req_key.domain, req_key.map, (int) req_key.keydat.keydat_len, req_key.keydat.keydat_val, reply_key_val->status); nis_reply(client, client_addr, client_addrlen, reply, reply_xdrs, reply_buf); } else { reply_key_val->status = YP_NOMORE; slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "next(%s/%s/%.*s) -> no more!\n", req_key.domain, req_key.map, (int) req_key.keydat.keydat_len, req_key.keydat.keydat_val); nis_reply(client, client_addr, client_addrlen, reply, reply_xdrs, reply_buf); } } else { /* XXX */ } } static void nis_master(struct plugin_state *state, int client, struct sockaddr *client_addr, socklen_t client_addrlen, XDR *request_xdrs, struct rpc_msg *reply, XDR *reply_xdrs, char *reply_buf, struct ypresp_master *reply_master) { struct ypreq_nokey req_nokey; memset(&req_nokey, 0, sizeof(req_nokey)); if (xdr_ypreq_nokey(request_xdrs, &req_nokey)) { reply_master->status = YP_TRUE; reply_master->master = "me, right here"; /* XXX */ slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "master(%s/%s) -> %s\n", req_nokey.domain, req_nokey.map, reply_master->master); nis_reply(client, client_addr, client_addrlen, reply, reply_xdrs, reply_buf); } else { /* XXX */ } } static void nis_order(struct plugin_state *state, int client, struct sockaddr *client_addr, socklen_t client_addrlen, XDR *request_xdrs, struct rpc_msg *reply, XDR *reply_xdrs, char *reply_buf, struct ypresp_order *reply_order) { struct ypreq_nokey req_nokey; memset(&req_nokey, 0, sizeof(req_nokey)); if (xdr_ypreq_nokey(request_xdrs, &req_nokey)) { reply_order->status = YP_TRUE; reply_order->ordernum = time(NULL); /* XXX */ slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "order(%s/%s) -> %d\n", req_nokey.domain, req_nokey.map, reply_order->ordernum); nis_reply(client, client_addr, client_addrlen, reply, reply_xdrs, reply_buf); } else { /* XXX */ } } static void nis_maplist(struct plugin_state *state, int client, struct sockaddr *client_addr, socklen_t client_addrlen, XDR *request_xdrs, struct rpc_msg *reply, XDR *reply_xdrs, char *reply_buf, struct ypresp_maplist *reply_maplist) { char *domain; struct ypmaplist *list; if (xdr_string(request_xdrs, &domain, YPMAXDOMAIN)) { reply_maplist->status = YP_TRUE; reply_maplist->list = NULL; /* XXX */ if (reply_maplist->list == NULL) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "maplist(%s) -> (none)\n", domain); } else { for (list = reply_maplist->list; list != NULL; list = list->next) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "maplist(%s) -> %s\n", domain, list->map); } } nis_reply(client, client_addr, client_addrlen, reply, reply_xdrs, reply_buf); } else { /* XXX */ } } static void nis_all(struct plugin_state *state, int client, struct sockaddr *client_addr, socklen_t client_addrlen, XDR *request_xdrs, struct rpc_msg *reply, XDR *reply_xdrs, char *reply_buf, bool_t *reply_more) { char domain[YPMAXDOMAIN + 1], *p; int i; struct ypreq_nokey req_nokey; struct ypresp_key_val reply_key_val; memset(&reply_key_val, 0, sizeof(reply_key_val)); *reply_more = FALSE; memset(&req_nokey, 0, sizeof(req_nokey)); if (xdr_ypreq_nokey(request_xdrs, &req_nokey)) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "all(%s/%s) -> %d\n", req_nokey.domain, req_nokey.map, *reply_more); *reply_more = TRUE; nis_reply_fragment(client, client_addr, client_addrlen, reply, reply_xdrs, reply_buf, TRUE, FALSE); xdr_setpos(reply_xdrs, 0); for (i = 0; i < 3; i++) { memset(&reply_key_val, 0, sizeof(reply_key_val)); reply_key_val.status = YP_TRUE; reply_key_val.keydat.keydat_val = DUMMY_KEY; reply_key_val.keydat.keydat_len = strlen(DUMMY_KEY); reply_key_val.valdat.valdat_val = DUMMY_VAL; reply_key_val.valdat.valdat_len = strlen(DUMMY_VAL); xdr_ypresp_key_val(reply_xdrs, &reply_key_val); if (i == 2) { *reply_more = FALSE; } xdr_bool(reply_xdrs, reply_more); } nis_reply_fragment(client, client_addr, client_addrlen, reply, reply_xdrs, reply_buf, FALSE, TRUE); } else { /* XXX */ } } void nis_process_request(struct plugin_state *state, int client, struct sockaddr *client_addr, socklen_t client_addrlen, char *request_buf, size_t request_buflen) { XDR request_xdrs, reply_xdrs, auth_xdrs; AUTH *request_auth, *reply_auth; char reply_buf[64000], auth_buf[64000]; struct rpc_msg request, reply; int superuser, send_reply, auth_flavor, auth_len; struct ypresp_val reply_val; struct ypresp_key_val reply_key_val; struct ypresp_master reply_master; struct ypresp_order reply_order; struct ypresp_maplist reply_maplist; struct accepted_reply *accepted; bool_t reply_bool; memset(&request_xdrs, 0, sizeof(request_xdrs)); memset(&reply_xdrs, 0, sizeof(reply_xdrs)); memset(&request, 0, sizeof(request)); memset(&reply, 0, sizeof(reply)); xdrmem_create(&request_xdrs, request_buf, request_buflen, XDR_DECODE); if (xdr_callmsg(&request_xdrs, &request) && (request.rm_direction == CALL)) { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "client request prog=%d,ver=%d,proc=%d\n", request.rm_call.cb_prog, request.rm_call.cb_vers, request.rm_call.cb_proc); /* verify the client's creds */ auth_flavor = request.rm_call.cb_cred.oa_flavor; switch (auth_flavor) { case AUTH_SYS: request_auth = authunix_create_default(); break; case AUTH_NONE: default: request_auth = authnone_create(); break; } if (auth_validate(request_auth, &request.rm_call.cb_cred)) { switch (auth_flavor) { case AUTH_SYS: slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "validated auth_sys creds\n"); superuser = 0; break; default: slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "validated other creds\n"); superuser = 0; break; } } else { slapi_log_error(SLAPI_LOG_PLUGIN, state->plugin_desc->spd_id, "failed to validate client creds\n"); superuser = 0; } auth_destroy(request_auth); /* setup authentication for our reply */ xdrmem_create(&auth_xdrs, auth_buf, sizeof(auth_buf), XDR_ENCODE); switch (auth_flavor) { case AUTH_SYS: reply_auth = authunix_create_default(); break; case AUTH_NONE: default: reply_auth = authnone_create(); break; } auth_marshall(reply_auth, &auth_xdrs); auth_destroy(reply_auth); auth_len = xdr_getpos(&auth_xdrs); xdr_destroy(&auth_xdrs); /* fill out the common fields */ reply.rm_xid = request.rm_xid; reply.rm_direction = REPLY; xdrmem_create(&reply_xdrs, reply_buf, sizeof(reply_buf), XDR_ENCODE); /* check if the request is meant for us */ if ((request.rm_direction != CALL) || (request.rm_call.cb_rpcvers != 2) || (request.rm_call.cb_prog != YPPROG) || (request.rm_call.cb_vers != YPVERS)) { reply.rm_reply.rp_stat = MSG_DENIED; reply.rm_reply.rp_rjct.rj_stat = RPC_MISMATCH; xdr_replymsg(&reply_xdrs, &reply); } else { /* default reply - success, no data */ reply.rm_reply.rp_stat = MSG_ACCEPTED; accepted = &reply.rm_reply.rp_acpt; accepted->ar_stat = SUCCESS; accepted->ar_results.where = NULL; accepted->ar_results.proc = xdr_void; /* call the right function */ switch (request.rm_call.cb_proc) { case YPPROC_NULL: /* do nothing */ break; case YPPROC_DOMAIN: case YPPROC_DOMAIN_NONACK: /* change reply type to be a boolean */ memset(&reply_bool, 0, sizeof(reply_bool)); accepted->ar_results.where = &reply_bool; accepted->ar_results.proc = xdr_bool; nis_domain(state, client, client_addr, client_addrlen, &request_xdrs, request.rm_call.cb_proc == YPPROC_DOMAIN, &reply, &reply_xdrs, reply_buf, &reply_bool); break; case YPPROC_MATCH: /* change reply type to a resp_val */ memset(&reply_val, 0, sizeof(reply_val)); accepted->ar_results.where = &reply_val; accepted->ar_results.proc = xdr_ypresp_val; nis_match(state, client, client_addr, client_addrlen, &request_xdrs, &reply, &reply_xdrs, reply_buf, &reply_val); break; case YPPROC_FIRST: /* change reply type to a resp_keyval */ memset(&reply_key_val, 0, sizeof(reply_key_val)); accepted->ar_results.where = &reply_key_val; accepted->ar_results.proc = xdr_ypresp_key_val; nis_first(state, client, client_addr, client_addrlen, &request_xdrs, &reply, &reply_xdrs, reply_buf, &reply_key_val); break; case YPPROC_NEXT: /* change reply type to a resp_keyval */ memset(&reply_key_val, 0, sizeof(reply_key_val)); accepted->ar_results.where = &reply_key_val; accepted->ar_results.proc = xdr_ypresp_key_val; nis_next(state, client, client_addr, client_addrlen, &request_xdrs, &reply, &reply_xdrs, reply_buf, &reply_key_val); break; case YPPROC_XFR: /* do nothing */ break; case YPPROC_CLEAR: /* do nothing */ break; case YPPROC_ALL: /* get all keys/vals */ memset(&reply_bool, 0, sizeof(reply_bool)); accepted->ar_results.where = &reply_bool; accepted->ar_results.proc = xdr_bool; /* sorry, only stream clients need apply */ if ((client_addr == NULL) && (client_addrlen == 0)) { nis_all(state, client, client_addr, client_addrlen, &request_xdrs, &reply, &reply_xdrs, reply_buf, &reply_bool); } break; case YPPROC_MASTER: /* change reply type to a resp_master */ memset(&reply_master, 0, sizeof(reply_master)); accepted->ar_results.where = &reply_master; accepted->ar_results.proc = xdr_ypresp_master; nis_master(state, client, client_addr, client_addrlen, &request_xdrs, &reply, &reply_xdrs, reply_buf, &reply_master); break; case YPPROC_ORDER: /* change reply type to a resp_order */ memset(&reply_order, 0, sizeof(reply_order)); accepted->ar_results.where = &reply_order; accepted->ar_results.proc = xdr_ypresp_order; nis_order(state, client, client_addr, client_addrlen, &request_xdrs, &reply, &reply_xdrs, reply_buf, &reply_order); break; case YPPROC_MAPLIST: /* change reply type to a resp_maplist */ memset(&reply_maplist, 0, sizeof(reply_maplist)); accepted->ar_results.where = &reply_maplist; accepted->ar_results.proc = xdr_ypresp_maplist; nis_maplist(state, client, client_addr, client_addrlen, &request_xdrs, &reply, &reply_xdrs, reply_buf, &reply_maplist); break; case YPPROC_NEWXFR: /* what? XXX */ /* fall through */ default: reply.rm_reply.rp_stat = MSG_DENIED; reply.rm_reply.rp_rjct.rj_stat = RPC_MISMATCH; nis_reply(client, client_addr, client_addrlen, &reply, &reply_xdrs, reply_buf); break; } } xdr_destroy(&reply_xdrs); } xdr_destroy(&request_xdrs); }