1 /* $OpenBSD: yp.c,v 1.14 2015/02/11 01:26:00 pelikan Exp $ */
4 * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <sys/types.h>
20 #include <sys/param.h>
21 #include <sys/queue.h>
22 #include <sys/socket.h>
23 #include <sys/select.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
41 #include <rpc/pmap_clnt.h>
42 #include <rpc/pmap_prot.h>
43 #include <rpc/pmap_rmt.h>
44 #include <rpcsvc/yp.h>
45 #include <rpcsvc/ypclnt.h>
49 void yp_dispatch(struct svc_req *, SVCXPRT *);
50 void yp_disable_events(void);
51 void yp_fd_event(int, short, void *);
52 int yp_check(struct svc_req *);
53 int yp_valid_domain(char *, struct ypresp_val *);
54 void yp_make_val(struct ypresp_val *, char *, int);
55 void yp_make_keyval(struct ypresp_key_val *, char *, char *);
57 static struct env *env;
60 TAILQ_ENTRY(yp_event) ye_entry;
61 struct event ye_event;
65 SVCXPRT *yp_trans_udp;
66 SVCXPRT *yp_trans_tcp;
67 TAILQ_HEAD(, yp_event) yd_events;
71 yp_disable_events(void)
75 while ((ye = TAILQ_FIRST(&env->sc_yp->yd_events)) != NULL) {
76 TAILQ_REMOVE(&env->sc_yp->yd_events, ye, ye_entry);
77 event_del(&ye->ye_event);
83 yp_enable_events(void)
88 for (i = 0; i < getdtablesize(); i++) {
89 if ((ye = calloc(1, sizeof(*ye))) == NULL)
91 event_set(&ye->ye_event, i, EV_READ, yp_fd_event, NULL);
92 event_add(&ye->ye_event, NULL);
93 TAILQ_INSERT_TAIL(&env->sc_yp->yd_events, ye, ye_entry);
98 yp_fd_event(int fd, short event, void *p)
100 svc_getreq_common(fd);
106 yp_init(struct env *x_env)
110 if ((yp = calloc(1, sizeof(*yp))) == NULL)
112 TAILQ_INIT(&yp->yd_events);
117 (void)pmap_unset(YPPROG, YPVERS);
119 if ((yp->yp_trans_udp = svcudp_create(RPC_ANYSOCK)) == NULL)
120 fatal("cannot create udp service");
121 if ((yp->yp_trans_tcp = svctcp_create(RPC_ANYSOCK, 0, 0)) == NULL)
122 fatal("cannot create tcp service");
124 if (!svc_register(yp->yp_trans_udp, YPPROG, YPVERS,
125 yp_dispatch, IPPROTO_UDP)) {
126 fatal("unable to register (YPPROG, YPVERS, udp)");
128 if (!svc_register(yp->yp_trans_tcp, YPPROG, YPVERS,
129 yp_dispatch, IPPROTO_TCP)) {
130 fatal("unable to register (YPPROG, YPVERS, tcp)");
135 * lots of inspiration from ypserv by Mats O Jansson
138 yp_dispatch(struct svc_req *req, SVCXPRT *trans)
140 xdrproc_t xdr_argument;
141 xdrproc_t xdr_result;
143 char *(*cb)(char *, struct svc_req *);
145 domainname ypproc_domain_2_arg;
146 domainname ypproc_domain_nonack_2_arg;
147 ypreq_key ypproc_match_2_arg;
148 ypreq_nokey ypproc_first_2_arg;
149 ypreq_key ypproc_next_2_arg;
150 ypreq_xfr ypproc_xfr_2_arg;
151 ypreq_nokey ypproc_all_2_arg;
152 ypreq_nokey ypproc_master_2_arg;
153 ypreq_nokey ypproc_order_2_arg;
154 domainname ypproc_maplist_2_arg;
157 xdr_argument = (xdrproc_t) xdr_void;
158 xdr_result = (xdrproc_t) xdr_void;
160 switch (req->rq_proc) {
162 xdr_argument = (xdrproc_t) xdr_void;
163 xdr_result = (xdrproc_t) xdr_void;
164 if (yp_check(req) == -1)
167 if (!svc_sendreply(trans, (xdrproc_t) xdr_void,
169 svcerr_systemerr(trans);
172 xdr_argument = (xdrproc_t) xdr_domainname;
173 xdr_result = (xdrproc_t) xdr_bool;
174 if (yp_check(req) == -1)
176 cb = (void *)ypproc_domain_2_svc;
178 case YPPROC_DOMAIN_NONACK:
179 xdr_argument = (xdrproc_t) xdr_domainname;
180 xdr_result = (xdrproc_t) xdr_bool;
181 if (yp_check(req) == -1)
183 cb = (void *)ypproc_domain_nonack_2_svc;
186 xdr_argument = (xdrproc_t) xdr_ypreq_key;
187 xdr_result = (xdrproc_t) xdr_ypresp_val;
188 if (yp_check(req) == -1)
190 cb = (void *)ypproc_match_2_svc;
193 xdr_argument = (xdrproc_t) xdr_ypreq_nokey;
194 xdr_result = (xdrproc_t) xdr_ypresp_key_val;
195 if (yp_check(req) == -1)
197 cb = (void *)ypproc_first_2_svc;
200 xdr_argument = (xdrproc_t) xdr_ypreq_key;
201 xdr_result = (xdrproc_t) xdr_ypresp_key_val;
202 if (yp_check(req) == -1)
204 cb = (void *)ypproc_next_2_svc;
207 if (yp_check(req) == -1)
209 svcerr_noproc(trans);
212 log_debug("ypproc_clear");
213 if (yp_check(req) == -1)
215 svcerr_noproc(trans);
218 log_debug("ypproc_all");
219 xdr_argument = (xdrproc_t) xdr_ypreq_nokey;
220 xdr_result = (xdrproc_t) xdr_ypresp_all;
221 if (yp_check(req) == -1)
223 cb = (void *)ypproc_all_2_svc;
226 log_debug("ypproc_master");
227 xdr_argument = (xdrproc_t) xdr_ypreq_nokey;
228 xdr_result = (xdrproc_t) xdr_ypresp_master;
229 if (yp_check(req) == -1)
231 cb = (void *)ypproc_master_2_svc;
234 log_debug("ypproc_order");
235 if (yp_check(req) == -1)
237 svcerr_noproc(trans);
240 log_debug("ypproc_maplist");
241 xdr_argument = (xdrproc_t) xdr_domainname;
242 xdr_result = (xdrproc_t) xdr_ypresp_maplist;
243 if (yp_check(req) == -1)
245 cb = (void *)ypproc_maplist_2_svc;
248 svcerr_noproc(trans);
251 (void)memset(&argument, 0, sizeof(argument));
253 if (!svc_getargs(trans, xdr_argument, (caddr_t)&argument)) {
254 svcerr_decode(trans);
257 result = (*cb)((char *)&argument, req);
258 if (result != NULL && !svc_sendreply(trans, xdr_result, result))
259 svcerr_systemerr(trans);
260 if (!svc_freeargs(trans, xdr_argument, (caddr_t)&argument)) {
262 * ypserv does it too.
264 fatal("unable to free arguments");
269 yp_check(struct svc_req *req)
271 struct sockaddr_in *caller;
273 caller = svc_getcaller(req->rq_xprt);
275 * We might want to know who we allow here.
281 yp_valid_domain(char *domain, struct ypresp_val *res)
283 if (domain == NULL) {
284 log_debug("NULL domain !");
287 if (strcmp(domain, env->sc_domainname) != 0) {
288 res->stat = YP_NODOM;
295 ypproc_domain_2_svc(domainname *arg, struct svc_req *req)
300 if (strcmp(*arg, env->sc_domainname) != 0)
306 ypproc_domain_nonack_2_svc(domainname *arg, struct svc_req *req)
310 if (strcmp(*arg, env->sc_domainname) != 0)
317 ypproc_match_2_svc(ypreq_key *arg, struct svc_req *req)
321 struct groupent gkey;
323 static struct ypresp_val res;
326 char key[YPMAXRECORD+1];
328 log_debug("matching '%.*s' in map %s", arg->key.keydat_len,
329 arg->key.keydat_val, arg->map);
331 if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
334 if (env->sc_user_names == NULL) {
341 if (arg->key.keydat_len > YPMAXRECORD) {
342 log_debug("argument too long");
345 memset(key, 0, sizeof(key));
346 (void)strncpy(key, arg->key.keydat_val, arg->key.keydat_len);
348 if (strcmp(arg->map, "passwd.byname") == 0 ||
349 strcmp(arg->map, "master.passwd.byname") == 0) {
351 if ((ue = RB_FIND(user_name_tree, env->sc_user_names,
357 yp_make_val(&res, ue->ue_line, 1);
359 } else if (strcmp(arg->map, "passwd.byuid") == 0 ||
360 strcmp(arg->map, "master.passwd.byuid") == 0) {
361 ukey.ue_uid = strtonum(key, 0, UID_MAX, &estr);
363 res.stat = YP_BADARGS;
367 if ((ue = RB_FIND(user_uid_tree, &env->sc_user_uids,
373 yp_make_val(&res, ue->ue_line, 1);
375 } else if (strcmp(arg->map, "group.bygid") == 0) {
376 gkey.ge_gid = strtonum(key, 0, GID_MAX, &estr);
378 res.stat = YP_BADARGS;
381 if ((ge = RB_FIND(group_gid_tree, &env->sc_group_gids,
387 yp_make_val(&res, ge->ge_line, 1);
389 } else if (strcmp(arg->map, "group.byname") == 0) {
391 if ((ge = RB_FIND(group_name_tree, env->sc_group_names,
397 yp_make_val(&res, ge->ge_line, 1);
399 } else if (strcmp(arg->map, "netid.byname") == 0) {
402 if (strncmp(bp, "unix.", strlen("unix.")) != 0) {
403 res.stat = YP_BADARGS;
407 bp += strlen("unix.");
410 res.stat = YP_BADARGS;
414 if (!(cp = strsep(&bp, "@"))) {
415 res.stat = YP_BADARGS;
419 if (strcmp(bp, arg->domain) != 0) {
420 res.stat = YP_BADARGS;
424 ukey.ue_uid = strtonum(cp, 0, UID_MAX, &estr);
426 res.stat = YP_BADARGS;
430 if ((ue = RB_FIND(user_uid_tree, &env->sc_user_uids,
436 yp_make_val(&res, ue->ue_netid_line, 0);
440 log_debug("unknown map %s", arg->map);
447 ypproc_first_2_svc(ypreq_nokey *arg, struct svc_req *req)
449 static struct ypresp_key_val res;
451 if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
454 if (strcmp(arg->map, "passwd.byname") == 0 ||
455 strcmp(arg->map, "master.passwd.byname") == 0) {
456 if (env->sc_user_lines == NULL)
459 yp_make_keyval(&res, env->sc_user_lines, env->sc_user_lines);
460 } else if (strcmp(arg->map, "group.byname") == 0) {
461 if (env->sc_group_lines == NULL)
464 yp_make_keyval(&res, env->sc_group_lines, env->sc_group_lines);
466 log_debug("unknown map %s", arg->map);
474 ypproc_next_2_svc(ypreq_key *arg, struct svc_req *req)
478 struct groupent gkey;
481 static struct ypresp_key_val res;
482 char key[YPMAXRECORD+1];
484 if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
487 if (strcmp(arg->map, "passwd.byname") == 0 ||
488 strcmp(arg->map, "master.passwd.byname") == 0) {
489 memset(key, 0, sizeof(key));
490 (void)strncpy(key, arg->key.keydat_val,
491 arg->key.keydat_len);
493 if ((ue = RB_FIND(user_name_tree, env->sc_user_names,
497 * the user might have been deleted in between calls
498 * to next since the tree may be modified by a reload.
499 * next should still return the next user in
500 * lexicographical order, hence insert the search key
501 * and look up the next field, then remove it again.
503 RB_INSERT(user_name_tree, env->sc_user_names, &ukey);
504 if ((ue = RB_NEXT(user_name_tree, &env->sc_user_names,
506 RB_REMOVE(user_name_tree, env->sc_user_names,
511 RB_REMOVE(user_name_tree, env->sc_user_names, &ukey);
513 line = ue->ue_line + (strlen(ue->ue_line) + 1);
514 line = line + (strlen(line) + 1);
515 yp_make_keyval(&res, line, line);
519 } else if (strcmp(arg->map, "group.byname") == 0) {
520 memset(key, 0, sizeof(key));
521 (void)strncpy(key, arg->key.keydat_val,
522 arg->key.keydat_len);
525 if ((ge = RB_FIND(group_name_tree, env->sc_group_names,
528 * canacar's trick reloaded.
530 RB_INSERT(group_name_tree, env->sc_group_names, &gkey);
531 if ((ge = RB_NEXT(group_name_tree, &env->sc_group_names,
533 RB_REMOVE(group_name_tree, env->sc_group_names,
538 RB_REMOVE(group_name_tree, env->sc_group_names, &gkey);
541 line = ge->ge_line + (strlen(ge->ge_line) + 1);
542 line = line + (strlen(line) + 1);
543 yp_make_keyval(&res, line, line);
546 log_debug("unknown map %s", arg->map);
553 ypproc_all_2_svc(ypreq_nokey *arg, struct svc_req *req)
555 static struct ypresp_all res;
557 if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
560 svcerr_auth(req->rq_xprt, AUTH_FAILED);
565 ypproc_master_2_svc(ypreq_nokey *arg, struct svc_req *req)
567 static struct ypresp_master res;
568 static char master[YPMAXPEER + 1];
570 memset(&res, 0, sizeof(res));
571 if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
574 if (gethostname(master, sizeof(master)) == 0) {
575 res.peer = (peername)master;
584 ypproc_maplist_2_svc(domainname *arg, struct svc_req *req)
591 { "passwd.byname", YPMAP_PASSWD_BYNAME },
592 { "passwd.byuid", YPMAP_PASSWD_BYUID },
593 { "master.passwd.byname", YPMAP_MASTER_PASSWD_BYNAME },
594 { "master.passwd.byuid", YPMAP_MASTER_PASSWD_BYUID },
595 { "group.byname", YPMAP_GROUP_BYNAME },
596 { "group.bygid", YPMAP_GROUP_BYGID },
597 { "netid.byname", YPMAP_NETID_BYNAME },
599 static ypresp_maplist res;
600 static struct ypmaplist maps[nitems(mapnames)];
602 if (yp_valid_domain(*arg, (struct ypresp_val *)&res) == -1)
607 for (i = 0; i < nitems(mapnames); i++) {
608 if (!(env->sc_flags & mapnames[i].cond))
610 maps[i].map = mapnames[i].name;
611 maps[i].next = res.maps;
619 yp_make_val(struct ypresp_val *res, char *line, int replacecolon)
621 static char buf[LINE_WIDTH];
623 memset(buf, 0, sizeof(buf));
626 line[strlen(line)] = ':';
627 (void)strlcpy(buf, line, sizeof(buf));
629 line[strcspn(line, ":")] = '\0';
630 log_debug("sending out %s", buf);
633 res->val.valdat_len = strlen(buf);
634 res->val.valdat_val = buf;
638 yp_make_keyval(struct ypresp_key_val *res, char *key, char *line)
640 static char keybuf[YPMAXRECORD+1];
641 static char buf[LINE_WIDTH];
643 memset(keybuf, 0, sizeof(keybuf));
644 memset(buf, 0, sizeof(buf));
646 (void)strlcpy(keybuf, key, sizeof(keybuf));
647 res->key.keydat_len = strlen(keybuf);
648 res->key.keydat_val = keybuf;
651 res->stat = YP_NOMORE;
655 line[strlen(line)] = ':';
656 (void)strlcpy(buf, line, sizeof(buf));
657 line[strcspn(line, ":")] = '\0';
658 log_debug("sending out %s => %s", keybuf, buf);
660 res->val.valdat_len = strlen(buf);
661 res->val.valdat_val = buf;