]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/ypldap/yp.c
Merge llvm-project release/17.x llvmorg-17.0.1-25-g098e653a5bed
[FreeBSD/FreeBSD.git] / usr.sbin / ypldap / yp.c
1 /*      $OpenBSD: yp.c,v 1.14 2015/02/11 01:26:00 pelikan Exp $ */
2 /*
3  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 #include <sys/types.h>
19 #include <sys/param.h>
20 #include <sys/queue.h>
21 #include <sys/socket.h>
22 #include <sys/select.h>
23 #include <sys/tree.h>
24
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27
28 #include <errno.h>
29 #include <event.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <pwd.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <limits.h>
37
38 #include <rpc/rpc.h>
39 #include <rpc/xdr.h>
40 #include <rpc/pmap_clnt.h>
41 #include <rpc/pmap_prot.h>
42 #include <rpc/pmap_rmt.h>
43 #include <rpcsvc/yp.h>
44 #include <rpcsvc/ypclnt.h>
45
46 #include "ypldap.h"
47
48 void    yp_dispatch(struct svc_req *, SVCXPRT *);
49 void    yp_disable_events(void);
50 void    yp_fd_event(int, short, void *);
51 int     yp_check(struct svc_req *);
52 int     yp_valid_domain(char *, struct ypresp_val *);
53 void    yp_make_val(struct ypresp_val *, char *, int);
54 void    yp_make_keyval(struct ypresp_key_val *, char *, char *);
55
56 static struct env       *env;
57
58 struct yp_event {
59         TAILQ_ENTRY(yp_event)    ye_entry;
60         struct event             ye_event;
61 };
62
63 struct yp_data {
64         SVCXPRT                 *yp_trans_udp;
65         SVCXPRT                 *yp_trans_tcp;
66         TAILQ_HEAD(, yp_event)   yd_events;
67 };
68
69 void
70 yp_disable_events(void)
71 {
72         struct yp_event *ye;
73
74         while ((ye = TAILQ_FIRST(&env->sc_yp->yd_events)) != NULL) {
75                 TAILQ_REMOVE(&env->sc_yp->yd_events, ye, ye_entry);
76                 event_del(&ye->ye_event);
77                 free(ye);
78         }
79 }
80
81 void
82 yp_enable_events(void)
83 {
84         int i;
85         struct yp_event *ye;
86
87         for (i = 0; i < getdtablesize(); i++) {
88                 if ((ye = calloc(1, sizeof(*ye))) == NULL)
89                         fatal(NULL);
90                 event_set(&ye->ye_event, i, EV_READ, yp_fd_event, NULL);
91                 event_add(&ye->ye_event, NULL);
92                 TAILQ_INSERT_TAIL(&env->sc_yp->yd_events, ye, ye_entry);
93         }
94 }
95
96 void
97 yp_fd_event(int fd, short event, void *p)
98 {
99         svc_getreq_common(fd);
100         yp_disable_events();
101         yp_enable_events();
102 }
103
104 void
105 yp_init(struct env *x_env)
106 {
107         struct yp_data  *yp;
108
109         if ((yp = calloc(1, sizeof(*yp))) == NULL)
110                 fatal(NULL);
111         TAILQ_INIT(&yp->yd_events);
112
113         env = x_env;
114         env->sc_yp = yp;
115         
116         (void)pmap_unset(YPPROG, YPVERS);
117
118         if ((yp->yp_trans_udp = svcudp_create(RPC_ANYSOCK)) == NULL)
119                 fatal("cannot create udp service");
120         if ((yp->yp_trans_tcp = svctcp_create(RPC_ANYSOCK, 0, 0)) == NULL)
121                 fatal("cannot create tcp service");
122
123         if (!svc_register(yp->yp_trans_udp, YPPROG, YPVERS,
124             yp_dispatch, IPPROTO_UDP)) {
125                 fatal("unable to register (YPPROG, YPVERS, udp)");
126         }
127         if (!svc_register(yp->yp_trans_tcp, YPPROG, YPVERS,
128             yp_dispatch, IPPROTO_TCP)) {
129                 fatal("unable to register (YPPROG, YPVERS, tcp)");
130         }
131 }
132
133 /*
134  * lots of inspiration from ypserv by Mats O Jansson
135  */
136 void
137 yp_dispatch(struct svc_req *req, SVCXPRT *trans)
138 {
139         xdrproc_t                xdr_argument;
140         xdrproc_t                xdr_result;
141         char                    *result;
142         char                    *(*cb)(char *, struct svc_req *);
143         union {
144                 domainname       ypproc_domain_2_arg;
145                 domainname       ypproc_domain_nonack_2_arg;
146                 ypreq_key        ypproc_match_2_arg;
147                 ypreq_nokey      ypproc_first_2_arg;
148                 ypreq_key        ypproc_next_2_arg;
149                 ypreq_xfr        ypproc_xfr_2_arg;
150                 ypreq_nokey      ypproc_all_2_arg;
151                 ypreq_nokey      ypproc_master_2_arg;
152                 ypreq_nokey      ypproc_order_2_arg;
153                 domainname       ypproc_maplist_2_arg;
154         } argument;
155
156         xdr_argument = (xdrproc_t) xdr_void;
157         xdr_result = (xdrproc_t) xdr_void;
158         cb = NULL;
159         switch (req->rq_proc) {
160         case YPPROC_NULL:
161                 xdr_argument = (xdrproc_t) xdr_void;
162                 xdr_result = (xdrproc_t) xdr_void;
163                 if (yp_check(req) == -1)
164                         return;
165                 result = NULL;
166                 if (!svc_sendreply(trans, (xdrproc_t) xdr_void,
167                     (void *)&result))
168                         svcerr_systemerr(trans);
169                 return;
170         case YPPROC_DOMAIN:
171                 xdr_argument = (xdrproc_t) xdr_domainname;
172                 xdr_result = (xdrproc_t) xdr_bool;
173                 if (yp_check(req) == -1)
174                         return;
175                 cb = (void *)ypproc_domain_2_svc;
176                 break;
177         case YPPROC_DOMAIN_NONACK:
178                 xdr_argument = (xdrproc_t) xdr_domainname;
179                 xdr_result = (xdrproc_t) xdr_bool;
180                 if (yp_check(req) == -1)
181                         return;
182                 cb = (void *)ypproc_domain_nonack_2_svc;
183                 break;
184         case YPPROC_MATCH:
185                 xdr_argument = (xdrproc_t) xdr_ypreq_key;
186                 xdr_result = (xdrproc_t) xdr_ypresp_val;
187                 if (yp_check(req) == -1)
188                         return;
189                 cb = (void *)ypproc_match_2_svc;
190                 break;
191         case YPPROC_FIRST:
192                 xdr_argument = (xdrproc_t) xdr_ypreq_nokey;
193                 xdr_result = (xdrproc_t) xdr_ypresp_key_val;
194                 if (yp_check(req) == -1)
195                         return;
196                 cb = (void *)ypproc_first_2_svc;
197                 break;
198         case YPPROC_NEXT:
199                 xdr_argument = (xdrproc_t) xdr_ypreq_key;
200                 xdr_result = (xdrproc_t) xdr_ypresp_key_val;
201                 if (yp_check(req) == -1)
202                         return;
203                 cb = (void *)ypproc_next_2_svc;
204                 break;
205         case YPPROC_XFR:
206                 if (yp_check(req) == -1)
207                         return;
208                 svcerr_noproc(trans);
209                 return;
210         case YPPROC_CLEAR:
211                 log_debug("ypproc_clear");
212                 if (yp_check(req) == -1)
213                         return;
214                 svcerr_noproc(trans);
215                 return;
216         case YPPROC_ALL:
217                 log_debug("ypproc_all");
218                 xdr_argument = (xdrproc_t) xdr_ypreq_nokey;
219                 xdr_result = (xdrproc_t) xdr_ypresp_all;
220                 if (yp_check(req) == -1)
221                         return;
222                 cb = (void *)ypproc_all_2_svc;
223                 break;
224         case YPPROC_MASTER:
225                 log_debug("ypproc_master");
226                 xdr_argument = (xdrproc_t) xdr_ypreq_nokey;
227                 xdr_result = (xdrproc_t) xdr_ypresp_master;
228                 if (yp_check(req) == -1)
229                         return;
230                 cb = (void *)ypproc_master_2_svc;
231                 break;
232         case YPPROC_ORDER:
233                 log_debug("ypproc_order");
234                 if (yp_check(req) == -1)
235                         return;
236                 svcerr_noproc(trans);
237                 return;
238         case YPPROC_MAPLIST:
239                 log_debug("ypproc_maplist");
240                 xdr_argument = (xdrproc_t) xdr_domainname;
241                 xdr_result = (xdrproc_t) xdr_ypresp_maplist;
242                 if (yp_check(req) == -1)
243                         return;
244                 cb = (void *)ypproc_maplist_2_svc;
245                 break;
246         default:
247                 svcerr_noproc(trans);
248                 return;
249         }
250         (void)memset(&argument, 0, sizeof(argument));
251
252         if (!svc_getargs(trans, xdr_argument, (caddr_t)&argument)) {
253                 svcerr_decode(trans);
254                 return;
255         }
256         result = (*cb)((char *)&argument, req);
257         if (result != NULL && !svc_sendreply(trans, xdr_result, result))
258                 svcerr_systemerr(trans);
259         if (!svc_freeargs(trans, xdr_argument, (caddr_t)&argument)) {
260                 /*
261                  * ypserv does it too.
262                  */
263                 fatal("unable to free arguments");
264         }
265 }
266
267 int
268 yp_check(struct svc_req *req)
269 {
270         /*
271          * We might want to know who we allow here.
272          */
273         return (0);
274 }
275
276 int
277 yp_valid_domain(char *domain, struct ypresp_val *res)
278 {
279         if (domain == NULL) {
280                 log_debug("NULL domain !");
281                 return (-1);
282         }
283         if (strcmp(domain, env->sc_domainname) != 0) {
284                 res->stat = YP_NODOM;
285                 return (-1);
286         }
287         return (0);
288 }
289
290 bool_t *
291 ypproc_domain_2_svc(domainname *arg, struct svc_req *req)
292 {
293         static bool_t   res;
294         
295         res = (bool_t)1;
296         if (strcmp(*arg, env->sc_domainname) != 0)
297                 res = (bool_t)0;
298         return (&res);
299 }
300
301 bool_t *
302 ypproc_domain_nonack_2_svc(domainname *arg, struct svc_req *req)
303 {
304         static bool_t   res;
305         
306         if (strcmp(*arg, env->sc_domainname) != 0)
307                 return NULL;
308         res = (bool_t)1;
309         return (&res);
310 }
311
312 ypresp_val *
313 ypproc_match_2_svc(ypreq_key *arg, struct svc_req *req)
314 {
315         struct userent           ukey;
316         struct userent          *ue;
317         struct groupent          gkey;
318         struct groupent         *ge;
319         static struct ypresp_val res;
320         const char              *estr;
321         char                    *bp, *cp;
322         char                     *key;
323
324         log_debug("matching '%.*s' in map %s", arg->key.keydat_len,
325            arg->key.keydat_val, arg->map);
326
327         if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
328                 return (&res);
329
330         if (env->sc_user_names == NULL) {
331                 /*
332                  * tree not ready.
333                  */
334                 return (NULL);
335         }
336
337         if (arg->key.keydat_len > YPMAXRECORD) {
338                 log_debug("argument too long");
339                 return (NULL);
340         }
341         key = calloc(arg->key.keydat_len + 1, 1);
342         if (key == NULL)
343                 return (NULL);
344         (void)strncpy(key, arg->key.keydat_val, arg->key.keydat_len);
345
346         if (strcmp(arg->map, "passwd.byname") == 0 ||
347             strcmp(arg->map, "master.passwd.byname") == 0) {
348                 ukey.ue_line = key;
349                 if ((ue = RB_FIND(user_name_tree, env->sc_user_names,
350                     &ukey)) == NULL) {
351                         res.stat = YP_NOKEY;
352                         goto out;
353                 }
354
355                 yp_make_val(&res, ue->ue_line, 1);
356                 goto out;
357         } else if (strcmp(arg->map, "passwd.byuid") == 0 ||
358                    strcmp(arg->map, "master.passwd.byuid") == 0) {
359                 ukey.ue_uid = strtonum(key, 0, UID_MAX, &estr); 
360                 if (estr) {
361                         res.stat = YP_BADARGS;
362                         goto out;
363                 }
364
365                 if ((ue = RB_FIND(user_uid_tree, &env->sc_user_uids,
366                     &ukey)) == NULL) {
367                         res.stat = YP_NOKEY;
368                         goto out;
369                 }
370
371                 yp_make_val(&res, ue->ue_line, 1);
372                 return (&res);
373         } else if (strcmp(arg->map, "group.bygid") == 0) {
374                 gkey.ge_gid = strtonum(key, 0, GID_MAX, &estr); 
375                 if (estr) {
376                         res.stat = YP_BADARGS;
377                         goto out;
378                 }
379                 if ((ge = RB_FIND(group_gid_tree, &env->sc_group_gids,
380                     &gkey)) == NULL) {
381                         res.stat = YP_NOKEY;
382                         goto out;
383                 }
384
385                 yp_make_val(&res, ge->ge_line, 1);
386                 return (&res);
387         } else if (strcmp(arg->map, "group.byname") == 0) {
388                 gkey.ge_line = key;
389                 if ((ge = RB_FIND(group_name_tree, env->sc_group_names,
390                     &gkey)) == NULL) {
391                         res.stat = YP_NOKEY;
392                         goto out;
393                 }
394
395                 yp_make_val(&res, ge->ge_line, 1);
396                 return (&res);
397         } else if (strcmp(arg->map, "netid.byname") == 0) {
398                 bp = cp = key;
399
400                 if (strncmp(bp, "unix.", strlen("unix.")) != 0) {
401                         res.stat = YP_BADARGS;
402                         goto out;
403                 }
404
405                 bp += strlen("unix.");
406
407                 if (*bp == '\0') {
408                         res.stat = YP_BADARGS;
409                         goto out;
410                 }
411
412                 if (!(cp = strsep(&bp, "@"))) {
413                         res.stat = YP_BADARGS;
414                         goto out;
415                 }
416
417                 if (strcmp(bp, arg->domain) != 0) {
418                         res.stat = YP_BADARGS;
419                         goto out;
420                 }
421
422                 ukey.ue_uid = strtonum(cp, 0, UID_MAX, &estr); 
423                 if (estr) {
424                         res.stat = YP_BADARGS;
425                         goto out;
426                 }
427
428                 if ((ue = RB_FIND(user_uid_tree, &env->sc_user_uids,
429                     &ukey)) == NULL) {
430                         res.stat = YP_NOKEY;
431                         goto out;
432                 }
433
434                 yp_make_val(&res, ue->ue_netid_line, 0);
435                 goto out;
436         
437         } else {
438                 log_debug("unknown map %s", arg->map);
439                 res.stat = YP_NOMAP;
440                 goto out;
441         }
442 out:
443         free(key);
444         return (&res);
445 }
446
447 ypresp_key_val *
448 ypproc_first_2_svc(ypreq_nokey *arg, struct svc_req *req)
449 {
450         static struct ypresp_key_val    res;
451
452         if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
453                 return (&res);
454
455         if (strcmp(arg->map, "passwd.byname") == 0 ||
456             strcmp(arg->map, "master.passwd.byname") == 0) {
457                 if (env->sc_user_lines == NULL)
458                         return (NULL);
459
460                 yp_make_keyval(&res, env->sc_user_lines, env->sc_user_lines);
461         } else if (strcmp(arg->map, "group.byname") == 0) {
462                 if (env->sc_group_lines == NULL)
463                         return (NULL);
464
465                 yp_make_keyval(&res, env->sc_group_lines, env->sc_group_lines);
466         } else {
467                 log_debug("unknown map %s", arg->map);
468                 res.stat = YP_NOMAP;
469         }
470
471         return (&res);
472 }
473
474 ypresp_key_val *
475 ypproc_next_2_svc(ypreq_key *arg, struct svc_req *req)
476 {
477         struct userent                   ukey;
478         struct userent                  *ue;
479         struct groupent                  gkey;
480         struct groupent                 *ge;
481         char                            *line;
482         static struct ypresp_key_val     res;
483         char                             *key;
484
485         if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
486                 return (&res);
487
488         key = NULL;
489         if (strcmp(arg->map, "passwd.byname") == 0 ||
490             strcmp(arg->map, "master.passwd.byname") == 0) {
491                 key = calloc(arg->key.keydat_len + 1, 1);
492                 if (key == NULL) {
493                         res.stat = YP_YPERR;
494                         return (&res);
495                 }
496                 (void)strncpy(key, arg->key.keydat_val,
497                     arg->key.keydat_len);
498                 ukey.ue_line = key;
499                 if ((ue = RB_FIND(user_name_tree, env->sc_user_names,
500                     &ukey)) == NULL) {
501                         /*
502                          * canacar's trick:
503                          * the user might have been deleted in between calls
504                          * to next since the tree may be modified by a reload.
505                          * next should still return the next user in
506                          * lexicographical order, hence insert the search key
507                          * and look up the next field, then remove it again.
508                          */
509                         RB_INSERT(user_name_tree, env->sc_user_names, &ukey);
510                         if ((ue = RB_NEXT(user_name_tree, &env->sc_user_names,
511                             &ukey)) == NULL) {
512                                 RB_REMOVE(user_name_tree, env->sc_user_names,
513                                     &ukey);
514                                 res.stat = YP_NOKEY;
515                                 free(key);
516                                 return (&res);
517                         }
518                         RB_REMOVE(user_name_tree, env->sc_user_names, &ukey);
519                 }
520                 line = ue->ue_line + (strlen(ue->ue_line) + 1);
521                 line = line + (strlen(line) + 1);
522                 yp_make_keyval(&res, line, line);
523                 free(key);
524                 return (&res);
525
526
527         } else if (strcmp(arg->map, "group.byname") == 0) {
528                 key = calloc(arg->key.keydat_len + 1, 1);
529                 if (key == NULL) {
530                         res.stat = YP_YPERR;
531                         return (&res);
532                 }
533                 (void)strncpy(key, arg->key.keydat_val,
534                     arg->key.keydat_len);
535                 
536                 gkey.ge_line = key;
537                 if ((ge = RB_FIND(group_name_tree, env->sc_group_names,
538                     &gkey)) == NULL) {
539                         /*
540                          * canacar's trick reloaded.
541                          */
542                         RB_INSERT(group_name_tree, env->sc_group_names, &gkey);
543                         if ((ge = RB_NEXT(group_name_tree, &env->sc_group_names,
544                             &gkey)) == NULL) {
545                                 RB_REMOVE(group_name_tree, env->sc_group_names,
546                                     &gkey);
547                                 res.stat = YP_NOKEY;
548                                 free(key);
549                                 return (&res);
550                         }
551                         RB_REMOVE(group_name_tree, env->sc_group_names, &gkey);
552                 }
553
554                 line = ge->ge_line + (strlen(ge->ge_line) + 1);
555                 line = line + (strlen(line) + 1);
556                 yp_make_keyval(&res, line, line);
557                 free(key);
558                 return (&res);
559         } else {
560                 log_debug("unknown map %s", arg->map);
561                 res.stat = YP_NOMAP;
562                 return (&res);
563         }
564 }
565
566 ypresp_all *
567 ypproc_all_2_svc(ypreq_nokey *arg, struct svc_req *req)
568 {
569         static struct ypresp_all        res;
570
571         if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
572                 return (&res);
573
574         svcerr_auth(req->rq_xprt, AUTH_FAILED);
575         return (NULL);
576 }
577
578 ypresp_master *
579 ypproc_master_2_svc(ypreq_nokey *arg, struct svc_req *req)
580 {
581         static struct ypresp_master      res;
582         static char master[YPMAXPEER + 1];
583
584         memset(&res, 0, sizeof(res));
585         if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
586                 return (&res);
587         
588         if (gethostname(master, sizeof(master)) == 0) {
589                 res.peer = (peername)master;
590                 res.stat = YP_TRUE;
591         } else
592                 res.stat = YP_NOKEY;
593
594         return (&res);
595 }
596
597 ypresp_maplist *
598 ypproc_maplist_2_svc(domainname *arg, struct svc_req *req)
599 {
600         size_t                   i;
601         static struct {
602                 char            *name;
603                 int              cond;
604         }                        mapnames[] = {
605                 { "passwd.byname",              YPMAP_PASSWD_BYNAME },
606                 { "passwd.byuid",               YPMAP_PASSWD_BYUID },
607                 { "master.passwd.byname",       YPMAP_MASTER_PASSWD_BYNAME },
608                 { "master.passwd.byuid",        YPMAP_MASTER_PASSWD_BYUID },
609                 { "group.byname",               YPMAP_GROUP_BYNAME },
610                 { "group.bygid",                YPMAP_GROUP_BYGID },
611                 { "netid.byname",               YPMAP_NETID_BYNAME },
612         };
613         static ypresp_maplist    res;
614         static struct ypmaplist  maps[nitems(mapnames)];
615         
616         if (yp_valid_domain(*arg, (struct ypresp_val *)&res) == -1)
617                 return (&res);
618
619         res.stat = YP_TRUE;
620         res.maps = NULL;
621         for (i = 0; i < nitems(mapnames); i++) {
622                 if (!(env->sc_flags & mapnames[i].cond))
623                         continue;
624                 maps[i].map = mapnames[i].name;
625                 maps[i].next = res.maps;
626                 res.maps = &maps[i];
627         }
628
629         return (&res);
630 }
631
632 void
633 yp_make_val(struct ypresp_val *res, char *line, int replacecolon)
634 {
635         static char              buf[LINE_WIDTH];
636
637         memset(buf, 0, sizeof(buf));
638
639         if (replacecolon)
640                 line[strlen(line)] = ':';
641         (void)strlcpy(buf, line, sizeof(buf));
642         if (replacecolon)
643                 line[strcspn(line, ":")] = '\0';
644         log_debug("sending out %s", buf);
645
646         res->stat = YP_TRUE;
647         res->val.valdat_len = strlen(buf);
648         res->val.valdat_val = buf;
649 }
650
651 void
652 yp_make_keyval(struct ypresp_key_val *res, char *key, char *line)
653 {
654         static char     keybuf[YPMAXRECORD+1];
655         static char     buf[LINE_WIDTH];
656
657         memset(keybuf, 0, sizeof(keybuf));
658         memset(buf, 0, sizeof(buf));
659         
660         (void)strlcpy(keybuf, key, sizeof(keybuf));
661         res->key.keydat_len = strlen(keybuf);
662         res->key.keydat_val = keybuf;
663
664         if (*line == '\0') {
665                 res->stat = YP_NOMORE;
666                 return;
667         }
668         res->stat = YP_TRUE;
669         line[strlen(line)] = ':';
670         (void)strlcpy(buf, line, sizeof(buf));
671         line[strcspn(line, ":")] = '\0';
672         log_debug("sending out %s => %s", keybuf, buf);
673
674         res->val.valdat_len = strlen(buf);
675         res->val.valdat_val = buf;
676 }