]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/ypldap/yp.c
Squash deprecation warning related to array.array(..).tostring()
[FreeBSD/FreeBSD.git] / usr.sbin / ypldap / yp.c
1 /*      $OpenBSD: yp.c,v 1.14 2015/02/11 01:26:00 pelikan Exp $ */
2 /*      $FreeBSD$ */
3 /*
4  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
5  *
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.
9  *
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.
17  */
18
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>
24 #include <sys/tree.h>
25
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28
29 #include <errno.h>
30 #include <event.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <pwd.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <limits.h>
38
39 #include <rpc/rpc.h>
40 #include <rpc/xdr.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>
46
47 #include "ypldap.h"
48
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 *);
56
57 static struct env       *env;
58
59 struct yp_event {
60         TAILQ_ENTRY(yp_event)    ye_entry;
61         struct event             ye_event;
62 };
63
64 struct yp_data {
65         SVCXPRT                 *yp_trans_udp;
66         SVCXPRT                 *yp_trans_tcp;
67         TAILQ_HEAD(, yp_event)   yd_events;
68 };
69
70 void
71 yp_disable_events(void)
72 {
73         struct yp_event *ye;
74
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);
78                 free(ye);
79         }
80 }
81
82 void
83 yp_enable_events(void)
84 {
85         int i;
86         struct yp_event *ye;
87
88         for (i = 0; i < getdtablesize(); i++) {
89                 if ((ye = calloc(1, sizeof(*ye))) == NULL)
90                         fatal(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);
94         }
95 }
96
97 void
98 yp_fd_event(int fd, short event, void *p)
99 {
100         svc_getreq_common(fd);
101         yp_disable_events();
102         yp_enable_events();
103 }
104
105 void
106 yp_init(struct env *x_env)
107 {
108         struct yp_data  *yp;
109
110         if ((yp = calloc(1, sizeof(*yp))) == NULL)
111                 fatal(NULL);
112         TAILQ_INIT(&yp->yd_events);
113
114         env = x_env;
115         env->sc_yp = yp;
116         
117         (void)pmap_unset(YPPROG, YPVERS);
118
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");
123
124         if (!svc_register(yp->yp_trans_udp, YPPROG, YPVERS,
125             yp_dispatch, IPPROTO_UDP)) {
126                 fatal("unable to register (YPPROG, YPVERS, udp)");
127         }
128         if (!svc_register(yp->yp_trans_tcp, YPPROG, YPVERS,
129             yp_dispatch, IPPROTO_TCP)) {
130                 fatal("unable to register (YPPROG, YPVERS, tcp)");
131         }
132 }
133
134 /*
135  * lots of inspiration from ypserv by Mats O Jansson
136  */
137 void
138 yp_dispatch(struct svc_req *req, SVCXPRT *trans)
139 {
140         xdrproc_t                xdr_argument;
141         xdrproc_t                xdr_result;
142         char                    *result;
143         char                    *(*cb)(char *, struct svc_req *);
144         union {
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;
155         } argument;
156
157         xdr_argument = (xdrproc_t) xdr_void;
158         xdr_result = (xdrproc_t) xdr_void;
159         cb = NULL;
160         switch (req->rq_proc) {
161         case YPPROC_NULL:
162                 xdr_argument = (xdrproc_t) xdr_void;
163                 xdr_result = (xdrproc_t) xdr_void;
164                 if (yp_check(req) == -1)
165                         return;
166                 result = NULL;
167                 if (!svc_sendreply(trans, (xdrproc_t) xdr_void,
168                     (void *)&result))
169                         svcerr_systemerr(trans);
170                 return;
171         case YPPROC_DOMAIN:
172                 xdr_argument = (xdrproc_t) xdr_domainname;
173                 xdr_result = (xdrproc_t) xdr_bool;
174                 if (yp_check(req) == -1)
175                         return;
176                 cb = (void *)ypproc_domain_2_svc;
177                 break;
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)
182                         return;
183                 cb = (void *)ypproc_domain_nonack_2_svc;
184                 break;
185         case YPPROC_MATCH:
186                 xdr_argument = (xdrproc_t) xdr_ypreq_key;
187                 xdr_result = (xdrproc_t) xdr_ypresp_val;
188                 if (yp_check(req) == -1)
189                         return;
190                 cb = (void *)ypproc_match_2_svc;
191                 break;
192         case YPPROC_FIRST:
193                 xdr_argument = (xdrproc_t) xdr_ypreq_nokey;
194                 xdr_result = (xdrproc_t) xdr_ypresp_key_val;
195                 if (yp_check(req) == -1)
196                         return;
197                 cb = (void *)ypproc_first_2_svc;
198                 break;
199         case YPPROC_NEXT:
200                 xdr_argument = (xdrproc_t) xdr_ypreq_key;
201                 xdr_result = (xdrproc_t) xdr_ypresp_key_val;
202                 if (yp_check(req) == -1)
203                         return;
204                 cb = (void *)ypproc_next_2_svc;
205                 break;
206         case YPPROC_XFR:
207                 if (yp_check(req) == -1)
208                         return;
209                 svcerr_noproc(trans);
210                 return;
211         case YPPROC_CLEAR:
212                 log_debug("ypproc_clear");
213                 if (yp_check(req) == -1)
214                         return;
215                 svcerr_noproc(trans);
216                 return;
217         case YPPROC_ALL:
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)
222                         return;
223                 cb = (void *)ypproc_all_2_svc;
224                 break;
225         case YPPROC_MASTER:
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)
230                         return;
231                 cb = (void *)ypproc_master_2_svc;
232                 break;
233         case YPPROC_ORDER:
234                 log_debug("ypproc_order");
235                 if (yp_check(req) == -1)
236                         return;
237                 svcerr_noproc(trans);
238                 return;
239         case YPPROC_MAPLIST:
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)
244                         return;
245                 cb = (void *)ypproc_maplist_2_svc;
246                 break;
247         default:
248                 svcerr_noproc(trans);
249                 return;
250         }
251         (void)memset(&argument, 0, sizeof(argument));
252
253         if (!svc_getargs(trans, xdr_argument, (caddr_t)&argument)) {
254                 svcerr_decode(trans);
255                 return;
256         }
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)) {
261                 /*
262                  * ypserv does it too.
263                  */
264                 fatal("unable to free arguments");
265         }
266 }
267
268 int
269 yp_check(struct svc_req *req)
270 {
271         struct sockaddr_in      *caller;
272
273         caller = svc_getcaller(req->rq_xprt);
274         /*
275          * We might want to know who we allow here.
276          */
277         return (0);
278 }
279
280 int
281 yp_valid_domain(char *domain, struct ypresp_val *res)
282 {
283         if (domain == NULL) {
284                 log_debug("NULL domain !");
285                 return (-1);
286         }
287         if (strcmp(domain, env->sc_domainname) != 0) {
288                 res->stat = YP_NODOM;
289                 return (-1);
290         }
291         return (0);
292 }
293
294 bool_t *
295 ypproc_domain_2_svc(domainname *arg, struct svc_req *req)
296 {
297         static bool_t   res;
298         
299         res = (bool_t)1;
300         if (strcmp(*arg, env->sc_domainname) != 0)
301                 res = (bool_t)0;
302         return (&res);
303 }
304
305 bool_t *
306 ypproc_domain_nonack_2_svc(domainname *arg, struct svc_req *req)
307 {
308         static bool_t   res;
309         
310         if (strcmp(*arg, env->sc_domainname) != 0)
311                 return NULL;
312         res = (bool_t)1;
313         return (&res);
314 }
315
316 ypresp_val *
317 ypproc_match_2_svc(ypreq_key *arg, struct svc_req *req)
318 {
319         struct userent           ukey;
320         struct userent          *ue;
321         struct groupent          gkey;
322         struct groupent         *ge;
323         static struct ypresp_val res;
324         const char              *estr;
325         char                    *bp, *cp;
326         char                     key[YPMAXRECORD+1];
327
328         log_debug("matching '%.*s' in map %s", arg->key.keydat_len,
329            arg->key.keydat_val, arg->map);
330
331         if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
332                 return (&res);
333
334         if (env->sc_user_names == NULL) {
335                 /*
336                  * tree not ready.
337                  */
338                 return (NULL);
339         }
340
341         if (arg->key.keydat_len > YPMAXRECORD) {
342                 log_debug("argument too long");
343                 return (NULL);
344         }
345         memset(key, 0, sizeof(key));
346         (void)strncpy(key, arg->key.keydat_val, arg->key.keydat_len);
347
348         if (strcmp(arg->map, "passwd.byname") == 0 ||
349             strcmp(arg->map, "master.passwd.byname") == 0) {
350                 ukey.ue_line = key;
351                 if ((ue = RB_FIND(user_name_tree, env->sc_user_names,
352                     &ukey)) == NULL) {
353                         res.stat = YP_NOKEY;
354                         return (&res);
355                 }
356
357                 yp_make_val(&res, ue->ue_line, 1);
358                 return (&res);
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); 
362                 if (estr) {
363                         res.stat = YP_BADARGS;
364                         return (&res);
365                 }
366
367                 if ((ue = RB_FIND(user_uid_tree, &env->sc_user_uids,
368                     &ukey)) == NULL) {
369                         res.stat = YP_NOKEY;
370                         return (&res);
371                 }
372
373                 yp_make_val(&res, ue->ue_line, 1);
374                 return (&res);
375         } else if (strcmp(arg->map, "group.bygid") == 0) {
376                 gkey.ge_gid = strtonum(key, 0, GID_MAX, &estr); 
377                 if (estr) {
378                         res.stat = YP_BADARGS;
379                         return (&res);
380                 }
381                 if ((ge = RB_FIND(group_gid_tree, &env->sc_group_gids,
382                     &gkey)) == NULL) {
383                         res.stat = YP_NOKEY;
384                         return (&res);
385                 }
386
387                 yp_make_val(&res, ge->ge_line, 1);
388                 return (&res);
389         } else if (strcmp(arg->map, "group.byname") == 0) {
390                 gkey.ge_line = key;
391                 if ((ge = RB_FIND(group_name_tree, env->sc_group_names,
392                     &gkey)) == NULL) {
393                         res.stat = YP_NOKEY;
394                         return (&res);
395                 }
396
397                 yp_make_val(&res, ge->ge_line, 1);
398                 return (&res);
399         } else if (strcmp(arg->map, "netid.byname") == 0) {
400                 bp = cp = key;
401
402                 if (strncmp(bp, "unix.", strlen("unix.")) != 0) {
403                         res.stat = YP_BADARGS;
404                         return (&res);
405                 }
406
407                 bp += strlen("unix.");
408
409                 if (*bp == '\0') {
410                         res.stat = YP_BADARGS;
411                         return (&res);
412                 }
413
414                 if (!(cp = strsep(&bp, "@"))) {
415                         res.stat = YP_BADARGS;
416                         return (&res);
417                 }
418
419                 if (strcmp(bp, arg->domain) != 0) {
420                         res.stat = YP_BADARGS;
421                         return (&res);
422                 }
423
424                 ukey.ue_uid = strtonum(cp, 0, UID_MAX, &estr); 
425                 if (estr) {
426                         res.stat = YP_BADARGS;
427                         return (&res);
428                 }
429
430                 if ((ue = RB_FIND(user_uid_tree, &env->sc_user_uids,
431                     &ukey)) == NULL) {
432                         res.stat = YP_NOKEY;
433                         return (&res);
434                 }
435
436                 yp_make_val(&res, ue->ue_netid_line, 0);
437                 return (&res);
438         
439         } else {
440                 log_debug("unknown map %s", arg->map);
441                 res.stat = YP_NOMAP;
442                 return (&res);
443         }
444 }
445
446 ypresp_key_val *
447 ypproc_first_2_svc(ypreq_nokey *arg, struct svc_req *req)
448 {
449         static struct ypresp_key_val    res;
450
451         if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
452                 return (&res);
453
454         if (strcmp(arg->map, "passwd.byname") == 0 ||
455             strcmp(arg->map, "master.passwd.byname") == 0) {
456                 if (env->sc_user_lines == NULL)
457                         return (NULL);
458
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)
462                         return (NULL);
463
464                 yp_make_keyval(&res, env->sc_group_lines, env->sc_group_lines);
465         } else {
466                 log_debug("unknown map %s", arg->map);
467                 res.stat = YP_NOMAP;
468         }
469
470         return (&res);
471 }
472
473 ypresp_key_val *
474 ypproc_next_2_svc(ypreq_key *arg, struct svc_req *req)
475 {
476         struct userent                   ukey;
477         struct userent                  *ue;
478         struct groupent                  gkey;
479         struct groupent                 *ge;
480         char                            *line;
481         static struct ypresp_key_val     res;
482         char                             key[YPMAXRECORD+1];
483
484         if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
485                 return (&res);
486
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);
492                 ukey.ue_line = key;
493                 if ((ue = RB_FIND(user_name_tree, env->sc_user_names,
494                     &ukey)) == NULL) {
495                         /*
496                          * canacar's trick:
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.
502                          */
503                         RB_INSERT(user_name_tree, env->sc_user_names, &ukey);
504                         if ((ue = RB_NEXT(user_name_tree, &env->sc_user_names,
505                             &ukey)) == NULL) {
506                                 RB_REMOVE(user_name_tree, env->sc_user_names,
507                                     &ukey);
508                                 res.stat = YP_NOKEY;
509                                 return (&res);
510                         }
511                         RB_REMOVE(user_name_tree, env->sc_user_names, &ukey);
512                 }
513                 line = ue->ue_line + (strlen(ue->ue_line) + 1);
514                 line = line + (strlen(line) + 1);
515                 yp_make_keyval(&res, line, line);
516                 return (&res);
517
518
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);
523                 
524                 gkey.ge_line = key;
525                 if ((ge = RB_FIND(group_name_tree, env->sc_group_names,
526                     &gkey)) == NULL) {
527                         /*
528                          * canacar's trick reloaded.
529                          */
530                         RB_INSERT(group_name_tree, env->sc_group_names, &gkey);
531                         if ((ge = RB_NEXT(group_name_tree, &env->sc_group_names,
532                             &gkey)) == NULL) {
533                                 RB_REMOVE(group_name_tree, env->sc_group_names,
534                                     &gkey);
535                                 res.stat = YP_NOKEY;
536                                 return (&res);
537                         }
538                         RB_REMOVE(group_name_tree, env->sc_group_names, &gkey);
539                 }
540
541                 line = ge->ge_line + (strlen(ge->ge_line) + 1);
542                 line = line + (strlen(line) + 1);
543                 yp_make_keyval(&res, line, line);
544                 return (&res);
545         } else {
546                 log_debug("unknown map %s", arg->map);
547                 res.stat = YP_NOMAP;
548                 return (&res);
549         }
550 }
551
552 ypresp_all *
553 ypproc_all_2_svc(ypreq_nokey *arg, struct svc_req *req)
554 {
555         static struct ypresp_all        res;
556
557         if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
558                 return (&res);
559
560         svcerr_auth(req->rq_xprt, AUTH_FAILED);
561         return (NULL);
562 }
563
564 ypresp_master *
565 ypproc_master_2_svc(ypreq_nokey *arg, struct svc_req *req)
566 {
567         static struct ypresp_master      res;
568         static char master[YPMAXPEER + 1];
569
570         memset(&res, 0, sizeof(res));
571         if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
572                 return (&res);
573         
574         if (gethostname(master, sizeof(master)) == 0) {
575                 res.peer = (peername)master;
576                 res.stat = YP_TRUE;
577         } else
578                 res.stat = YP_NOKEY;
579
580         return (&res);
581 }
582
583 ypresp_maplist *
584 ypproc_maplist_2_svc(domainname *arg, struct svc_req *req)
585 {
586         size_t                   i;
587         static struct {
588                 char            *name;
589                 int              cond;
590         }                        mapnames[] = {
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 },
598         };
599         static ypresp_maplist    res;
600         static struct ypmaplist  maps[nitems(mapnames)];
601         
602         if (yp_valid_domain(*arg, (struct ypresp_val *)&res) == -1)
603                 return (&res);
604
605         res.stat = YP_TRUE;
606         res.maps = NULL;
607         for (i = 0; i < nitems(mapnames); i++) {
608                 if (!(env->sc_flags & mapnames[i].cond))
609                         continue;
610                 maps[i].map = mapnames[i].name;
611                 maps[i].next = res.maps;
612                 res.maps = &maps[i];
613         }
614
615         return (&res);
616 }
617
618 void
619 yp_make_val(struct ypresp_val *res, char *line, int replacecolon)
620 {
621         static char              buf[LINE_WIDTH];
622
623         memset(buf, 0, sizeof(buf));
624
625         if (replacecolon)
626                 line[strlen(line)] = ':';
627         (void)strlcpy(buf, line, sizeof(buf));
628         if (replacecolon)
629                 line[strcspn(line, ":")] = '\0';
630         log_debug("sending out %s", buf);
631
632         res->stat = YP_TRUE;
633         res->val.valdat_len = strlen(buf);
634         res->val.valdat_val = buf;
635 }
636
637 void
638 yp_make_keyval(struct ypresp_key_val *res, char *key, char *line)
639 {
640         static char     keybuf[YPMAXRECORD+1];
641         static char     buf[LINE_WIDTH];
642
643         memset(keybuf, 0, sizeof(keybuf));
644         memset(buf, 0, sizeof(buf));
645         
646         (void)strlcpy(keybuf, key, sizeof(keybuf));
647         res->key.keydat_len = strlen(keybuf);
648         res->key.keydat_val = keybuf;
649
650         if (*line == '\0') {
651                 res->stat = YP_NOMORE;
652                 return;
653         }
654         res->stat = YP_TRUE;
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);
659
660         res->val.valdat_len = strlen(buf);
661         res->val.valdat_val = buf;
662 }