1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 *
21 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
22 * Use is subject to license terms.
23 *
24 * Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T
25 * All Rights Reserved
26 *
27 * Portions of this source code were derived from Berkeley
28 * 4.3 BSD under license from the Regents of the University of
29 * California.
30 */
31 /*
32 * Copyright (c) 2016 by Delphix. All rights reserved.
33 */
34
35 #define _SVID_GETTOD
36 #include <sys/time.h>
37 extern int gettimeofday(struct timeval *);
38
39 #include <sys/types.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <malloc.h>
43 #include <errno.h>
44 #include <signal.h>
45 #include <limits.h>
46 #include <stdlib.h>
47 #include <unistd.h>
48 #include <sys/types.h>
49 #include <sys/wait.h>
50 #include <sys/stat.h>
51 #include <ctype.h>
52 #include <dirent.h>
53 #include <rpc/rpc.h>
54 #include <rpc/nettype.h>
55 #include <rpc/rpcb_prot.h>
56 #include <rpc/rpcb_clnt.h>
57 #include <sys/systeminfo.h>
58 #include <sys/select.h>
59 #include "ypsym.h"
60 #include "ypdefs.h"
61 #include "yp_b.h"
62 #include "shim.h"
63 #include "yptol.h"
64
65
66 #ifdef DEBUG
67 #undef YPPROG
68 #define YPPROG ((ulong_t)109999)
69 #undef YPBINDPROG
70 #define YPBINDPROG ((ulong_t)109998)
71 #endif
72
73 #define INTER_TRY 12 /* Seconds between tries */
74 #define PORTMAP_TIME 30 /* Seconds before decide its down */
75 #define TIMEOUT INTER_TRY*4 /* Total time for timeout */
76 #define CUR_PAR 4 /* Total parallal yppushes */
77 #define MIN_GRACE 25 /* select timeout and minimum grace */
78 #define GRACE_PERIOD 800 /* Total seconds we'll wait for */
79 /* responses from ypxfrs, yes */
80 /* virginia yp map transfers */
81 /* can take a long time, we */
82 /* only worry if the slave */
83 /* crashes ... */
84
85 USE_YPDBPATH
86 static char *pusage;
87 static char *domain = NULL;
88 static char *host = NULL;
89 static char my_name[YPMAXPEER +1];
90 static char default_domain_name[YPMAXDOMAIN];
91 static char domain_alias[MAXNAMLEN]; /* nickname for domain - */
92 /* used in sysv filesystems */
93 static char map_alias[MAXNAMLEN]; /* nickname for map - */
94 /* used in sysv filesystems */
95 static char *map = NULL;
96 static bool verbose = FALSE;
97 static bool onehost = FALSE;
98 static bool oldxfr = FALSE;
99 static bool callback_timeout = FALSE; /* set when a callback times out */
100 int grace_period = GRACE_PERIOD;
101 int curpar = CUR_PAR; /* should be set by other stuff */
102 static char ypmapname[1024]; /* Used to check for map's existence */
103
104 static struct timeval intertry = {
105 INTER_TRY, /* Seconds */
106 0 /* Microseconds */
107 };
108 static struct timeval timeout = {
109 TIMEOUT, /* Seconds */
110 0 /* Microseconds */
111 };
112 static SVCXPRT *transport4;
113 static SVCXPRT *transport6;
114 struct server {
115 struct server *pnext;
116 struct dom_binding domb;
117 char svc_name[YPMAXPEER+1];
118 unsigned long xactid;
119 unsigned short state;
120 unsigned long status;
121 bool oldvers;
122 int start_time;
123 };
124 #define n_conf dom_binding->ypbind_nconf
125 #define svc_addr dom_binding->ypbind_svcaddr
126 static struct server *server_list = (struct server *)NULL;
127 static struct server *active_list = (struct server *)NULL;
128
129 /* State values for server.state field */
130
131 #define SSTAT_INIT 0
132 #define SSTAT_CALLED 1
133 #define SSTAT_RESPONDED 2
134 #define SSTAT_PROGNOTREG 3
135 #define SSTAT_RPC 4
136 #define SSTAT_RSCRC 5
137 #define SSTAT_SYSTEM 6
138
139 static char err_usage[] =
140 "Usage:\n\typpush [-p <par>] [-d <domainname>] [-h <hostname>] [-v] map\n";
141 static char err_bad_args[] =
142 "The %s argument is bad.\n";
143 static char err_cant_get_kname[] =
144 "Can't get %s from system call.\n";
145 static char err_null_kname[] =
146 "The %s hasn't been set on this machine.\n";
147 static char err_bad_domainname[] = "domainname";
148 static char err_cant_bind[] =
149 "Can't find a yp server for domain %s. Reason: %s.\n";
150 static char err_cant_build_serverlist[] =
151 "Can't build server list from map \"ypservers\". Reason: %s.\n";
152 static char err_cant_find_host[] =
153 "Can't find host %s in map \"ypservers\".\n";
154 /*
155 * State_duple table. All messages should take 1 arg - the node name.
156 */
157 struct state_duple {
158 int state;
159 char *state_msg;
160 };
161 static struct state_duple state_duples[] = {
162 {SSTAT_INIT, "Internal error trying to talk to %s."},
163 {SSTAT_CALLED, "%s has been called."},
164 {SSTAT_RESPONDED, "%s (v1 ypserv) sent an old-style request."},
165 {SSTAT_PROGNOTREG, "nis server not registered at %s."},
166 {SSTAT_RPC, "RPC error to %s: "},
167 {SSTAT_RSCRC, "Local resource allocation failure - can't talk to %s."},
168 {SSTAT_SYSTEM, "System error talking to %s: "},
169 {0, (char *)NULL}
170 };
171 /*
172 * Status_duple table. No messages should require any args.
173 */
174 struct status_duple {
175 long status;
176 char *status_msg;
177 };
178 static struct status_duple status_duples[] = {
179 {YPPUSH_SUCC, "Map successfully transferred."},
180 {YPPUSH_AGE,
181 "Transfer not done: master's version isn't newer."},
182 {YPPUSH_NOMAP, "Failed - ypxfr there can't find a server for map."},
183 {YPPUSH_NODOM, "Failed - domain isn't supported."},
184 {YPPUSH_RSRC, "Failed - local resource allocation failure."},
185 {YPPUSH_RPC, "Failed - ypxfr had an RPC failure"},
186 {YPPUSH_MADDR, "Failed - ypxfr couldn't get the map master's address."},
187 {YPPUSH_YPERR, "Failed - nis server or map format error."},
188 {YPPUSH_BADARGS, "Failed - args to ypxfr were bad."},
189 {YPPUSH_DBM, "Failed - dbm operation on map failed."},
190 {YPPUSH_FILE, "Failed - file I/O operation on map failed"},
191 {YPPUSH_SKEW, "Failed - map version skew during transfer."},
192 {YPPUSH_CLEAR,
193 "Map successfully transferred, but ypxfr \
194 couldn't send \"Clear map\" to ypserv "},
195 {YPPUSH_FORCE,
196 "Failed - no local order number in map - use -f flag to ypxfr."},
197 {YPPUSH_XFRERR, "Failed - ypxfr internal error."},
198 {YPPUSH_REFUSED, "Failed - Transfer request refused."},
199 {YPPUSH_NOALIAS,
200 "Failed - System V domain/map alias not in alias file."},
201 {0, (char *)NULL}
202 };
203 /*
204 * rpcerr_duple table
205 */
206 struct rpcerr_duple {
207 enum clnt_stat rpc_stat;
208 char *rpc_msg;
209 };
210 static struct rpcerr_duple rpcerr_duples[] = {
211 {RPC_SUCCESS, "RPC success"},
212 {RPC_CANTENCODEARGS, "RPC Can't encode args"},
213 {RPC_CANTDECODERES, "RPC Can't decode results"},
214 {RPC_CANTSEND, "RPC Can't send"},
215 {RPC_CANTRECV, "RPC Can't recv"},
216 {RPC_TIMEDOUT, "NIS server registered, but does not respond"},
217 {RPC_VERSMISMATCH, "RPC version mismatch"},
218 {RPC_AUTHERROR, "RPC auth error"},
219 {RPC_PROGUNAVAIL, "RPC remote program unavailable"},
220 {RPC_PROGVERSMISMATCH, "RPC program mismatch"},
221 {RPC_PROCUNAVAIL, "RPC unknown procedure"},
222 {RPC_CANTDECODEARGS, "RPC Can't decode args"},
223 {RPC_UNKNOWNHOST, "unknown host"},
224 {RPC_RPCBFAILURE, "rpcbind failure (host is down?)"},
225 {RPC_PROGNOTREGISTERED, "RPC prog not registered"},
226 {RPC_SYSTEMERROR, "RPC system error"},
227 {RPC_SUCCESS, (char *)NULL} /* Duplicate rpc_stat */
228 /* unused in list-end */
229 /* entry */
230 };
231
232 static void get_default_domain_name(void);
233 static void get_command_line_args(int argc, char **argv);
234 static unsigned short send_message(struct server *ps,
235 unsigned long program, long *err);
236 static void make_server_list(void);
237 static void one_host_list(void);
238 static void add_server(char *sname, int namelen);
239 static int generate_callback(unsigned long *program);
240 static void xactid_seed(unsigned long *xactid);
241 static void main_loop(unsigned long program);
242 static void listener_exit(unsigned long program, int stat);
243 static void listener_dispatch(struct svc_req *rqstp, SVCXPRT *transp);
244 static void print_state_msg(struct server *s, long e);
245 static void print_callback_msg(struct server *s);
246 static void rpcerr_msg(enum clnt_stat e);
247 static void get_xfr_response(SVCXPRT *transp);
248
249 #ifdef SYSVCONFIG
250 extern void sysvconfig(void);
251 #endif
252 extern int yp_getalias(char *key, char *key_alias, int maxlen);
253 extern int getdomainname(char *, int);
254
255 extern struct rpc_createerr rpc_createerr;
256 extern CLIENT *__yp_clnt_create_rsvdport();
257
258 int
main(int argc,char ** argv)259 main(int argc, char **argv)
260 {
261 unsigned long program;
262 struct stat64 sbuf;
263
264 get_command_line_args(argc, argv);
265
266 if (!domain) {
267 get_default_domain_name();
268 }
269
270 #ifdef SYSVCONFIG
271 sysvconfig();
272 #endif
273
274 if (yp_getalias(domain, domain_alias, NAME_MAX) != 0)
275 fprintf(stderr, "domain alias for %s not found\n", domain);
276 if (yp_getalias(map, map_alias, MAXALIASLEN) != 0)
277 fprintf(stderr, "map alias for %s not found\n", map);
278
279 /* check to see if the map exists in this domain */
280 if (is_yptol_mode())
281 sprintf(ypmapname, "%s/%s/%s%s.dir", ypdbpath, domain_alias,
282 NTOL_PREFIX, map_alias);
283 else
284 sprintf(ypmapname, "%s/%s/%s.dir", ypdbpath, domain_alias,
285 map_alias);
286 if (stat64(ypmapname, &sbuf) < 0) {
287 fprintf(stderr, "yppush: Map does not exist.\n");
288 exit(1);
289 }
290
291 if (onehost) {
292 one_host_list();
293 } else {
294 make_server_list();
295 }
296
297 /*
298 * All process exits after the call to generate_callback should be
299 * through listener_exit(program, status), not exit(status), so the
300 * transient server can get unregistered with the portmapper.
301 */
302
303 if (!generate_callback(&program)) {
304 fprintf(stderr, "Can't set up transient callback server.\n");
305 }
306
307 main_loop(program);
308
309 listener_exit(program, 0);
310
311 /* NOTREACHED */
312 return (0);
313 }
314
315 /*
316 * This does the command line parsing.
317 */
318 static void
get_command_line_args(int argc,char ** argv)319 get_command_line_args(int argc, char **argv)
320 {
321 pusage = err_usage;
322 argv++;
323
324 if (argc < 2) {
325 fprintf(stderr, pusage);
326 exit(1);
327 }
328
329 while (--argc) {
330 if ((*argv)[0] == '-') {
331 switch ((*argv)[1]) {
332 case 'v':
333 verbose = TRUE;
334 argv++;
335 break;
336 case 'd':
337 if (argc > 1) {
338 argv++;
339 argc--;
340 domain = *argv;
341 argv++;
342 if (((int)strlen(domain)) >
343 YPMAXDOMAIN) {
344 fprintf(stderr,
345 err_bad_args,
346 err_bad_domainname);
347 exit(1);
348 }
349 } else {
350 fprintf(stderr, pusage);
351 exit(1);
352 }
353 break;
354 case 'h':
355 if (argc > 1) {
356 onehost = TRUE;
357 argv++;
358 argc--;
359 host = *argv;
360 argv++;
361 } else {
362 fprintf(stderr, pusage);
363 exit(1);
364 }
365 break;
366
367 case 'p':
368
369 if (argc > 1) {
370 argv++;
371 argc--;
372 if (sscanf(*argv, "%d", &curpar) != 1) {
373 (void) fprintf(stderr, pusage);
374 exit(1);
375 }
376 argv++;
377 if (curpar < 1) {
378 (void) fprintf(stderr, pusage);
379 exit(1);
380 }
381 } else {
382 (void) fprintf(stderr, pusage);
383 exit(1);
384 }
385 break;
386
387 default:
388 fprintf(stderr, pusage);
389 exit(1);
390 }
391 } else {
392 if (!map) {
393 map = *argv;
394 } else {
395 fprintf(stderr, pusage);
396 exit(1);
397 }
398 argv++;
399 }
400 }
401
402 if (!map) {
403 fprintf(stderr, pusage);
404 exit(1);
405 }
406 }
407
408 /*
409 * This gets the local kernel domainname, and sets the global domain to it.
410 */
411 static void
get_default_domain_name(void)412 get_default_domain_name(void)
413 {
414 if (!getdomainname(default_domain_name, YPMAXDOMAIN)) {
415 domain = default_domain_name;
416 } else {
417 fprintf(stderr, err_cant_get_kname, err_bad_domainname);
418 exit(1);
419 }
420
421 if ((int)strlen(domain) == 0) {
422 fprintf(stderr, err_null_kname, err_bad_domainname);
423 exit(1);
424 }
425 }
426
427 /*
428 * This verifies that the hostname supplied by the user is in the map
429 * "ypservers" then calls add_server to make it the only entry on the
430 * list of servers.
431 */
432 static void
one_host_list(void)433 one_host_list(void)
434 {
435 char *key;
436 int keylen;
437 char *val;
438 int vallen;
439 int err;
440 char *ypservers = "ypservers";
441
442 if (verbose) {
443 printf("Verifying YP server: %s\n", host);
444 fflush(stdout);
445 }
446
447 if (err = yp_bind(domain_alias)) {
448 fprintf(stderr, err_cant_bind, domain, yperr_string(err));
449 exit(1);
450 }
451
452 keylen = strlen(host);
453
454 if (yp_match(domain_alias, ypservers, host, keylen,
455 &val, &vallen)) {
456 fprintf(stderr, err_cant_find_host, host);
457 exit(1);
458 }
459
460 add_server(host, keylen);
461 }
462
463 /*
464 * This uses yp operations to retrieve each server name in the map
465 * "ypservers". add_server is called for each one to add it to the list of
466 * servers.
467 */
468 static void
make_server_list(void)469 make_server_list(void)
470 {
471 char *key;
472 int keylen;
473 char *outkey;
474 int outkeylen;
475 char *val;
476 int vallen;
477 int err;
478 char *ypservers = "ypservers";
479 int count;
480
481 if (verbose) {
482 printf("Finding YP servers: ");
483 fflush(stdout);
484 count = 4;
485 }
486
487 if (err = yp_bind(domain_alias)) {
488 fprintf(stderr, err_cant_bind, domain, yperr_string(err));
489 exit(1);
490 }
491
492 if (err = yp_first(domain_alias, ypservers, &outkey, &outkeylen,
493 &val, &vallen)) {
494 fprintf(stderr, err_cant_build_serverlist, yperr_string(err));
495 exit(1);
496 }
497
498 for (;;) {
499 add_server(outkey, outkeylen);
500 if (verbose) {
501 printf(" %s", outkey);
502 fflush(stdout);
503 if (count++ == 8) {
504 printf("\n");
505 count = 0;
506 }
507 }
508 free(val);
509 key = outkey;
510 keylen = outkeylen;
511
512 if (err = yp_next(domain_alias, ypservers, key, keylen,
513 &outkey, &outkeylen, &val, &vallen)) {
514
515 if (err == YPERR_NOMORE) {
516 break;
517 } else {
518 fprintf(stderr, err_cant_build_serverlist,
519 yperr_string(err));
520 exit(1);
521 }
522 }
523
524 free(key);
525 }
526 if (count != 0) {
527 if (verbose)
528 printf("\n");
529 }
530 }
531
532 /*
533 * This adds a single server to the server list.
534 */
535 static void
add_server(char * sname,int namelen)536 add_server(char *sname, int namelen)
537 {
538 struct server *ps;
539 static unsigned long seq;
540 static unsigned long xactid = 0;
541
542 if (strcmp(sname, my_name) == 0)
543 return;
544
545 if (xactid == 0) {
546 xactid_seed(&xactid);
547 }
548
549 if ((ps = (struct server *)malloc((unsigned)sizeof (struct server)))
550 == (struct server *)NULL) {
551 perror("yppush: malloc failure");
552 exit(1);
553 }
554
555 sname[namelen] = '\0';
556 strcpy(ps->svc_name, sname);
557 ps->state = SSTAT_INIT;
558 ps->status = 0;
559 ps->oldvers = FALSE;
560 ps->xactid = xactid + seq++;
561 ps->pnext = server_list;
562 server_list = ps;
563 }
564
565 /*
566 * This sets the base range for the transaction ids used in speaking the the
567 * server ypxfr processes.
568 */
569 static void
xactid_seed(unsigned long * xactid)570 xactid_seed(unsigned long *xactid)
571 {
572 struct timeval t;
573
574 if (gettimeofday(&t) == -1) {
575 perror("yppush gettimeofday failure");
576 *xactid = 1234567;
577 } else {
578 *xactid = t.tv_sec;
579 }
580 }
581
582 /*
583 * This generates the channel which will be used as the listener process'
584 * service rendezvous point, and comes up with a transient program number
585 * for the use of the RPC messages from the ypxfr processes.
586 */
587 static int
generate_callback(unsigned long * program)588 generate_callback(unsigned long *program)
589 {
590 unsigned long prognum = 0x40000000, maxprognum;
591 union {
592 unsigned long p;
593 unsigned char b[sizeof (unsigned long)];
594 } u;
595 int ret, i;
596 struct netconfig *nc4, *nc6, *nc;
597 SVCXPRT *trans;
598
599 nc4 = getnetconfigent("udp");
600 nc6 = getnetconfigent("udp6");
601 if (nc4 == 0 && nc6 == 0) {
602 fprintf(stderr,
603 "yppush: Could not get udp or udp6 netconfig entry\n");
604 exit(1);
605 }
606
607 transport4 = (nc4 == 0) ? 0 : svc_tli_create(RPC_ANYFD, nc4, 0, 0, 0);
608 transport6 = (nc6 == 0) ? 0 : svc_tli_create(RPC_ANYFD, nc6, 0, 0, 0);
609 if (transport4 == 0 && transport6 == 0) {
610 fprintf(stderr, "yppush: Could not create server handle(s)\n");
611 exit(1);
612 }
613
614 /* Find the maximum possible program number using an unsigned long */
615 for (i = 0; i < sizeof (u.b); i++)
616 u.b[i] = 0xff;
617 maxprognum = u.p;
618
619 if (transport4 != 0) {
620 trans = transport4;
621 nc = nc4;
622 } else {
623 trans = transport6;
624 nc = nc6;
625 }
626 while (prognum < maxprognum && (ret =
627 rpcb_set(prognum, YPPUSHVERS, nc, &trans->xp_ltaddr)) == 0)
628 prognum++;
629
630 if (ret == 0) {
631 fprintf(stderr, "yppush: Could not create callback service\n");
632 exit(1);
633 } else {
634 if (trans == transport4 && transport6 != 0) {
635 ret = rpcb_set(prognum, YPPUSHVERS, nc6,
636 &transport6->xp_ltaddr);
637 if (ret == 0) {
638 fprintf(stderr,
639 "yppush: Could not create udp6 callback service\n");
640 exit(1);
641 }
642 }
643 *program = prognum;
644 }
645
646 return (ret);
647 }
648
649 /*
650 * This is the main loop. Send messages to each server,
651 * and then wait for a response.
652 */
653
654
655 int
add_to_active()656 add_to_active()
657 {
658 struct server *ps;
659 ps = server_list;
660 if (ps == NULL)
661 return (0);
662 server_list = server_list->pnext; /* delete from server_list */
663 ps->pnext = active_list;
664 active_list = ps;
665 return (1);
666 }
667
668 int
delete_active(in)669 delete_active(in)
670 struct server *in;
671 {
672 struct server *p;
673 struct server *n;
674 if (in == active_list) {
675 active_list = active_list->pnext;
676 return (1);
677 }
678 p = active_list;
679 for (n = active_list; n; n = n->pnext) {
680 if (in == n) {
681 p->pnext = n->pnext;
682 return (0);
683
684 }
685 p = n;
686 }
687 return (-1);
688 }
689
690 void
main_loop(program)691 main_loop(program)
692 unsigned long program;
693 {
694 pollfd_t *pollset = NULL;
695 int npollfds = 0;
696 int pollret;
697 struct server *ps;
698 long error;
699 int hpar; /* this times par count */
700 int i;
701 int j;
702 int time_now;
703 int docb;
704 int actives = 0;
705 int dead = 0;
706
707 if (grace_period < MIN_GRACE)
708 grace_period = MIN_GRACE;
709 if (transport4 != 0) {
710 if (!svc_reg(transport4, program, YPPUSHVERS,
711 listener_dispatch, 0)) {
712 fprintf(stderr,
713 "Can't set up transient udp callback server.\n");
714 }
715 }
716 if (transport6 != 0) {
717 if (!svc_reg(transport6, program, YPPUSHVERS,
718 listener_dispatch, 0)) {
719 fprintf(stderr,
720 "Can't set up transient udp6 callback server.\n");
721 }
722 }
723 for (;;) {
724 time_now = time(0);
725 if (server_list == NULL) {
726 actives = 0;
727 dead = 0;
728 for (ps = active_list; ps; ps = ps->pnext)
729 if (ps->state == SSTAT_CALLED) {
730 if ((time_now - ps->start_time) <
731 grace_period)
732 actives++;
733 else
734 dead++;
735 }
736 if (actives == 0) {
737 if (verbose) {
738 printf("terminating %d dead\n", dead);
739 fflush(stdout);
740 }
741
742 for (ps = active_list; ps; ps = ps->pnext)
743 if (ps->state == SSTAT_CALLED) {
744 if ((time_now - ps->start_time)
745 >= grace_period) {
746 if (verbose) {
747 printf(
748 "no response from %s -- grace of %d seconds expired.\n",
749 ps->svc_name, grace_period);
750 fflush(stdout);
751 }
752 fprintf(stderr,
753 "No response from ypxfr on %s\n", ps->svc_name);
754 }
755 }
756 break;
757 }
758 }
759 actives = 0;
760 for (ps = active_list; ps; ps = ps->pnext) {
761 if (ps->state == SSTAT_CALLED) {
762 if ((time_now - ps->start_time)
763 < grace_period) {
764 actives++;
765
766 if (verbose) {
767 printf(
768 "No response yet from ypxfr on %s\n", ps->svc_name);
769 fflush(stdout);
770 }
771 }
772 } else {
773 if (verbose) {
774 printf("Deactivating %s\n",
775 ps->svc_name);
776 fflush(stdout);
777 }
778 delete_active(ps);
779 }
780 }
781
782 /* add someone to the active list keep up with curpar */
783 for (i = 0; i < (curpar - actives); i++) {
784 if (add_to_active()) {
785 ps = active_list;
786 ps->state = send_message(ps, program, &error);
787 print_state_msg(ps, error);
788 if (ps->state != SSTAT_CALLED)
789 delete_active(ps); /* zorch it */
790 else
791 ps->start_time = time(0); /* set time */
792 }
793 }
794 docb = 0;
795 for (ps = active_list; ps; ps = ps->pnext)
796 if (ps->state == SSTAT_CALLED) {
797 docb = 1;
798 break;
799 }
800 if (docb == 0) {
801 if (verbose) {
802 printf("No one to wait for this pass.\n");
803 fflush(stdout);
804 }
805 continue; /* try curpar more */
806 }
807
808 if (npollfds != svc_max_pollfd) {
809 pollset = realloc(pollset,
810 sizeof (pollfd_t) * svc_max_pollfd);
811 npollfds = svc_max_pollfd;
812 }
813
814 /*
815 * Get existing array of pollfd's, should really compress
816 * this but it shouldn't get very large (or sparse).
817 */
818 (void) memcpy(pollset, svc_pollfd,
819 sizeof (pollfd_t) * svc_max_pollfd);
820
821 errno = 0;
822 switch (pollret = poll(pollset, npollfds, MIN_GRACE * 1000)) {
823 case -1:
824 if (errno != EINTR) {
825 (void) perror("main loop select");
826 }
827 break;
828
829 case 0:
830 if (verbose) {
831 (void) printf("timeout in main loop select.\n");
832 fflush(stdout);
833 }
834 break;
835
836 default:
837 svc_getreq_poll(pollset, pollret);
838 break;
839 } /* switch */
840 } /* for */
841 }
842
843 /*
844 * This does the listener process cleanup and process exit.
845 */
846 static void
listener_exit(unsigned long program,int stat)847 listener_exit(unsigned long program, int stat)
848 {
849 svc_unreg(program, YPPUSHVERS);
850 exit(stat);
851 }
852
853 /*
854 * This is the listener process' RPC service dispatcher.
855 */
856 static void
listener_dispatch(struct svc_req * rqstp,SVCXPRT * transp)857 listener_dispatch(struct svc_req *rqstp, SVCXPRT *transp)
858 {
859 switch (rqstp->rq_proc) {
860
861 case YPPUSHPROC_NULL:
862 if (!svc_sendreply(transp, xdr_void, 0)) {
863 fprintf(stderr, "Can't reply to rpc call.\n");
864 }
865 break;
866
867 case YPPUSHPROC_XFRRESP:
868 get_xfr_response(transp);
869 break;
870
871 default:
872 svcerr_noproc(transp);
873 break;
874 }
875 }
876
877
878 /*
879 * This dumps a server state message to stdout. It is called in cases where
880 * we have no expectation of receiving a callback from the remote ypxfr.
881 */
882 static void
print_state_msg(struct server * s,long e)883 print_state_msg(struct server *s, long e)
884 {
885 struct state_duple *sd;
886
887 if (s->state == SSTAT_SYSTEM)
888 return; /* already printed */
889
890 if (!verbose && (s->state == SSTAT_RESPONDED ||
891 s->state == SSTAT_CALLED))
892 return;
893
894 for (sd = state_duples; sd->state_msg; sd++) {
895 if (sd->state == s->state) {
896 printf(sd->state_msg, s->svc_name);
897
898 if (s->state == SSTAT_RPC) {
899 rpcerr_msg((enum clnt_stat) e);
900 }
901
902 printf("\n");
903 fflush(stdout);
904 return;
905 }
906 }
907
908 fprintf(stderr, "yppush: Bad server state value %d.\n", s->state);
909 }
910
911 /*
912 * This dumps a transfer status message to stdout. It is called in
913 * response to a received RPC message from the called ypxfr.
914 */
915 static void
print_callback_msg(struct server * s)916 print_callback_msg(struct server *s)
917 {
918 register struct status_duple *sd;
919
920 if (!verbose &&
921 (s->status == YPPUSH_AGE) ||
922 (s->status == YPPUSH_SUCC))
923
924 return;
925
926 for (sd = status_duples; sd->status_msg; sd++) {
927
928 if (sd->status == s->status) {
929 printf("Status received from ypxfr on %s:\n\t%s\n",
930 s->svc_name, sd->status_msg);
931 fflush(stdout);
932 return;
933 }
934 }
935
936 fprintf(stderr, "yppush listener: Garbage transaction "
937 "status (value %d) from ypxfr on %s.\n",
938 (int)s->status, s->svc_name);
939 }
940
941 /*
942 * This dumps an RPC error message to stdout. This is basically a rewrite
943 * of clnt_perrno, but writes to stdout instead of stderr.
944 */
945 static void
rpcerr_msg(enum clnt_stat e)946 rpcerr_msg(enum clnt_stat e)
947 {
948 struct rpcerr_duple *rd;
949
950 for (rd = rpcerr_duples; rd->rpc_msg; rd++) {
951
952 if (rd->rpc_stat == e) {
953 printf(rd->rpc_msg);
954 return;
955 }
956 }
957
958 fprintf(stderr, "Bad error code passed to rpcerr_msg: %d.\n", e);
959 }
960
961 /*
962 * This picks up the response from the ypxfr process which has been started
963 * up on the remote node. The response status must be non-zero, otherwise
964 * the status will be set to "ypxfr error".
965 */
966 static void
get_xfr_response(SVCXPRT * transp)967 get_xfr_response(SVCXPRT *transp)
968 {
969 struct yppushresp_xfr resp;
970 register struct server *s;
971
972 if (!svc_getargs(transp, (xdrproc_t)xdr_yppushresp_xfr,
973 (caddr_t)&resp)) {
974 svcerr_decode(transp);
975 return;
976 }
977
978 if (!svc_sendreply(transp, xdr_void, 0)) {
979 (void) fprintf(stderr, "Can't reply to rpc call.\n");
980 }
981
982 for (s = active_list; s; s = s->pnext) {
983
984 if (s->xactid == resp.transid) {
985 s->status = resp.status ? resp.status: YPPUSH_XFRERR;
986 print_callback_msg(s);
987 s->state = SSTAT_RESPONDED;
988 return;
989 }
990 }
991 }
992
993 /*
994 * This sends a message to a single ypserv process. The return value is
995 * a state value. If the RPC call fails because of a version
996 * mismatch, we'll assume that we're talking to a version 1 ypserv process,
997 * and will send it an old "YPPROC_GET" request, as was defined in the
998 * earlier version of yp_prot.h
999 */
1000 static unsigned short
send_message(struct server * ps,unsigned long program,long * err)1001 send_message(struct server *ps, unsigned long program, long *err)
1002 {
1003 struct ypreq_newxfr req;
1004 struct ypreq_xfr oldreq;
1005 enum clnt_stat s;
1006 struct rpc_err rpcerr;
1007
1008 if ((ps->domb.dom_client = __yp_clnt_create_rsvdport(ps->svc_name,
1009 YPPROG, YPVERS, (char *)NULL, 0, 0)) == NULL) {
1010
1011 if (rpc_createerr.cf_stat == RPC_PROGNOTREGISTERED) {
1012 return (SSTAT_PROGNOTREG);
1013 } else {
1014 printf("Error talking to %s: ", ps->svc_name);
1015 rpcerr_msg(rpc_createerr.cf_stat);
1016 printf("\n");
1017 fflush(stdout);
1018 return (SSTAT_SYSTEM);
1019 }
1020 }
1021
1022 if (sysinfo(SI_HOSTNAME, my_name, sizeof (my_name)) == -1) {
1023 return (SSTAT_RSCRC);
1024 }
1025
1026 if (!oldxfr) {
1027 req.ypxfr_domain = domain;
1028 req.ypxfr_map = map;
1029 req.ypxfr_ordernum = 0;
1030 req.ypxfr_owner = my_name;
1031 req.name = ps->svc_name;
1032 /*
1033 * the creation of field req.name, instead of ypreq_xfr (old)
1034 * req.port, does not make any sense. it doesn't give any
1035 * information to receiving ypserv except its own name !!
1036 * new ypserv duplicates work for YPPROC_XFR and YPPROC_NEWXFR
1037 */
1038 req.transid = ps->xactid;
1039 req.proto = program;
1040 s = (enum clnt_stat) clnt_call(ps->domb.dom_client,
1041 YPPROC_NEWXFR, (xdrproc_t)xdr_ypreq_newxfr, (caddr_t)&req,
1042 xdr_void, 0, timeout);
1043 }
1044
1045 clnt_geterr(ps->domb.dom_client, &rpcerr);
1046
1047 if (s == RPC_PROCUNAVAIL) {
1048 oldreq.ypxfr_domain = domain;
1049 oldreq.ypxfr_map = map;
1050 oldreq.ypxfr_ordernum = 0;
1051 oldreq.ypxfr_owner = my_name;
1052 oldreq.transid = ps->xactid;
1053 oldreq.proto = program;
1054 oldreq.port = 0;
1055 s = (enum clnt_stat) clnt_call(ps->domb.dom_client,
1056 YPPROC_XFR, (xdrproc_t)xdr_ypreq_xfr, (caddr_t)&oldreq,
1057 xdr_void, 0, timeout);
1058 clnt_geterr(ps->domb.dom_client, &rpcerr);
1059 }
1060
1061 clnt_destroy(ps->domb.dom_client);
1062
1063 if (s == RPC_SUCCESS) {
1064 return (SSTAT_CALLED);
1065 } else {
1066 *err = (long)rpcerr.re_status;
1067 return (SSTAT_RPC);
1068 }
1069 /*NOTREACHED*/
1070 }
1071
1072 /*
1073 * FUNCTION: is_yptol_mode();
1074 *
1075 * DESCRIPTION: Determines if we should run in N2L or traditional mode based
1076 * on the presence of the N2L mapping file.
1077 *
1078 * This is a copy of a function from libnisdb. If more than this
1079 * one function become required it may be worth linking the
1080 * entire lib.
1081 *
1082 * INPUTS: Nothing
1083 *
1084 * OUTPUTS: TRUE = Run in N2L mode
1085 * FALSE = Run in traditional mode.
1086 */
1087 bool_t
is_yptol_mode()1088 is_yptol_mode()
1089 {
1090 struct stat filestat;
1091
1092 if (stat(NTOL_MAP_FILE, &filestat) != -1)
1093 return (TRUE);
1094
1095 return (FALSE);
1096 }
1097