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, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 *
22 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29 /*
30 * Portions of this source code were derived from Berkeley
31 * under license from the Regents of the University of
32 * California.
33 */
34
35 #pragma ident "%Z%%M% %I% %E% SMI"
36
37 /*
38 * This is a user command which gets a NIS data base from some running
39 * server, and gets it to the local site by using the normal NIS client
40 * enumeration functions. The map is copied to a temp name, then the real
41 * map is removed and the temp map is moved to the real name. ypxfr then
42 * sends a "YPPROC_CLEAR" message to the local server to insure that he will
43 * not hold a removed map open, so serving an obsolete version.
44 *
45 * ypxfr [ -h <host> ] [ -d <domainname> ]
46 * [ -s <domainname> ] [-f] [-c] [-C tid prot name] map
47 *
48 * If the host is ommitted, ypxfr will attempt to discover the master by
49 * using normal NIS services. If it can't get the record, it will use
50 * the address of the callback, if specified. If the host is specified
51 * as an internet address, no NIS services need to be locally available.
52 *
53 * If the domain is not specified, the default domain of the local machine
54 * is used.
55 *
56 * If the -f flag is used, the transfer will be done even if the master's
57 * copy is not newer than the local copy.
58 *
59 * The -c flag suppresses the YPPROC_CLEAR request to the local ypserv. It
60 * may be used if ypserv isn't currently running to suppress the error message.
61 *
62 * The -C flag is used to pass callback information to ypxfr when it is
63 * activated by ypserv. The callback information is used to send a
64 * yppushresp_xfr message with transaction id "tid" to a yppush process
65 * speaking a transient protocol number "prot". The yppush program is
66 * running on the host "name".
67 *
68 * The -s option is used to specify a source domain which may be
69 * different from the destination domain, for transfer of maps
70 * that are identical in different domains (e.g. services.byname)
71 *
72 */
73
74 #include <ndbm.h>
75 #undef NULL
76 #define DATUM
77
78 #include <stdio.h>
79 #include <errno.h>
80 #include <time.h>
81 #include <ctype.h>
82 #include <netdb.h>
83 #include <netconfig.h>
84 #include <netdir.h>
85 #include <rpc/rpc.h>
86 #include <sys/file.h>
87 #include <sys/stat.h>
88 #include <dirent.h>
89 #include <rpcsvc/ypclnt.h>
90 #include <rpcsvc/yp_prot.h>
91 #include <unistd.h>
92 #include <stdlib.h>
93 #include <rpcsvc/nis.h>
94 #include "ypdefs.h"
95 #include "yp_b.h"
96 #include "shim.h"
97 #include "yptol.h"
98
99 USE_YP_MASTER_NAME
100 USE_YP_SECURE
101 USE_YP_INTERDOMAIN
102 USE_YP_LAST_MODIFIED
103 USE_YPDBPATH
104 USE_DBM
105
106 #define PARANOID 1 /* make sure maps have the right # entries */
107
108 #define CALLINTER_TRY 10 /* Seconds between callback tries */
109 #define CALLTIMEOUT CALLINTER_TRY*6 /* Total timeout for callback */
110
111 DBM *db;
112
113 /* ypxfr never uses N2L mode */
114 bool_t yptol_mode = FALSE;
115
116 int debug = FALSE;
117 int treepush = FALSE;
118 #define TREEPUSH 1
119 int defwrite = TRUE;
120
121 char *domain = NULL;
122 char *source = NULL;
123 char *map = NULL;
124 char *master = NULL;
125 char *pushhost = NULL;
126 /*
127 * The name of the xfer peer as specified as a
128 * -h option, -C name option or from querying the NIS
129 */
130 struct dom_binding master_server; /* To talk to above */
131 unsigned int master_prog_vers; /* YPVERS (barfs at YPOLDVERS !) */
132 char *master_name = NULL; /* Map's master as contained in the map */
133 unsigned *master_version = NULL; /* Order number as contained in the map */
134 char *master_ascii_version; /* ASCII order number as contained in the map */
135 bool fake_master_version = FALSE;
136 /*
137 * TRUE only if there's no order number in
138 * the map, and the user specified -f
139 */
140 bool force = FALSE; /* TRUE iff user specified -f flag */
141 bool logging = FALSE; /* TRUE iff no tty, but log file exists */
142 bool check_count = FALSE; /* TRUE causes counts to be checked */
143 bool send_clear = TRUE; /* FALSE iff user specified -c flag */
144 bool callback = FALSE;
145 /*
146 * TRUE iff -C flag set. tid, proto and name
147 * will be set to point to the command line args.
148 */
149 bool secure_map = FALSE; /* TRUE if there is yp_secure in the map */
150 bool interdomain_map = FALSE;
151 /*
152 * TRUE if there is yp_interdomain in either
153 * the local or the master version of the map
154 */
155 int interdomain_sz = 0; /* Size of the interdomain value */
156 #define UDPINTER_TRY 10 /* Seconds between tries for udp */
157 #define UDPTIMEOUT UDPINTER_TRY*4 /* Total timeout for udp */
158 #define CALLINTER_TRY 10 /* Seconds between callback tries */
159 #define CALLTIMEOUT CALLINTER_TRY*6 /* Total timeout for callback */
160 struct timeval udp_timeout = { UDPTIMEOUT, 0};
161 struct timeval tcp_timeout = { 180, 0}; /* Timeout for map enumeration */
162
163 char *interdomain_value; /* place to store the interdomain value */
164 char *tid;
165 char *proto;
166 int entry_count; /* counts entries in the map */
167 char logfile[] = "/var/yp/ypxfr.log";
168 static char err_usage[] =
169 "Usage:\n\
170 ypxfr [-f] [ -h host ] [ -d domainname ]\n\
171 [ -s domainname ] [-c] [-C tid prot servname ] map\n\n\
172 where\n\
173 -f forces transfer even if the master's copy is not newer.\n\
174 host is the server from where the map should be transfered\n\
175 -d domainname is specified if other than the default domain\n\
176 -s domainname is a source for the map that is same across domains\n\
177 -c inhibits sending a \"Clear map\" message to the local ypserv.\n\
178 -C is for use only by ypserv to pass callback information.\n";
179 char err_bad_args[] =
180 "%s argument is bad.\n";
181 char err_cant_get_kname[] =
182 "Can't get %s back from system call.\n";
183 char err_null_kname[] =
184 "%s hasn't been set on this machine.\n";
185 char err_bad_hostname[] = "hostname";
186 char err_bad_mapname[] = "mapname";
187 char err_bad_domainname[] = "domainname";
188 char err_udp_failure[] =
189 "Can't set up a udp connection to ypserv on host %s.\n";
190 char yptempname_prefix[] = "ypxfr_map.";
191 char ypbkupname_prefix[] = "ypxfr_bkup.";
192
193 void get_command_line_args();
194 bool bind_to_server();
195 bool ping_server();
196 bool get_private_recs();
197 bool get_order();
198 bool get_v1order();
199 bool get_v2order();
200 bool get_misc_recs();
201 bool get_master_name();
202 bool get_v1master_name();
203 bool get_v2master_name();
204 void find_map_master();
205 bool move_map();
206 unsigned get_local_version();
207 void mkfilename();
208 void mk_tmpname();
209 bool get_map();
210 bool add_private_entries();
211 bool new_mapfiles();
212 void del_mapfiles();
213 void set_output();
214 void logprintf();
215 bool send_ypclear();
216 void xfr_exit();
217 void send_callback();
218 int ypall_callback();
219 int map_yperr_to_pusherr();
220 extern CLIENT *__yp_clnt_create_rsvdport();
221
222 bool_t is_yptol_mode();
223
224 extern int errno;
225
226
227 /*
228 * This is the mainline for the ypxfr process.
229 */
230
231 int
main(argc,argv)232 main(argc, argv)
233 int argc;
234 char **argv;
235
236 {
237
238 static char default_domain_name[YPMAXDOMAIN];
239 static unsigned big = 0xffffffff;
240 int status;
241
242 set_output();
243
244 /*
245 * Inter-process lock synchronization structure. Since slave servers
246 * get their maps from another NIS server rather than LDAP they can
247 * never run in N2L mode. We thus do not have to init the update
248 * locking mechanism.
249 */
250 if (init_lock_map() == FALSE) {
251 exit(1);
252 }
253
254 get_command_line_args(argc, argv);
255
256 if (!domain) {
257
258 if (!getdomainname(default_domain_name, YPMAXDOMAIN)) {
259 domain = default_domain_name;
260 } else {
261 logprintf(err_cant_get_kname,
262 err_bad_domainname);
263 xfr_exit(YPPUSH_RSRC);
264 }
265
266 if (strlen(domain) == 0) {
267 logprintf(err_null_kname,
268 err_bad_domainname);
269 xfr_exit(YPPUSH_RSRC);
270 }
271 }
272 if (!source)
273 source = domain;
274
275 if (!master) {
276 find_map_master();
277 }
278 /*
279 * if we were unable to get the master name, either from
280 * the -h option or from -C "name" option or from NIS,
281 * we are doomed !
282 */
283 if (!master) {
284 xfr_exit(YPPUSH_MADDR);
285 }
286
287 if (!bind_to_server(master, &master_server,
288 &master_prog_vers, &status)) {
289 xfr_exit(status);
290 }
291
292 if (!get_private_recs(&status)) {
293 xfr_exit(status);
294 }
295
296 if (!master_version) {
297
298 if (force) {
299 master_version = &big;
300 fake_master_version = TRUE;
301 } else {
302 logprintf(
303 "Can't get order number for map %s from server at %s: use the -f flag.\n",
304 map, master);
305 xfr_exit(YPPUSH_FORCE);
306 }
307 }
308
309 if (!move_map(&status)) {
310 xfr_exit(status);
311 }
312
313 if (send_clear && !send_ypclear(&status)) {
314 xfr_exit(status);
315 }
316
317 if (logging) {
318 logprintf("Transferred map %s from %s (%d entries).\n",
319 map, master, entry_count);
320 }
321
322 xfr_exit(YPPUSH_SUCC);
323 return (0);
324 /* NOTREACHED */
325 }
326
327 /*
328 * This decides whether we're being run interactively or not, and, if not,
329 * whether we're supposed to be logging or not. If we are logging, it sets
330 * up stderr to point to the log file, and sets the "logging"
331 * variable. If there's no logging, the output goes in the bit bucket.
332 * Logging output differs from interactive output in the presence of a
333 * timestamp, present only in the log file. stderr is reset, too, because it
334 * it's used by various library functions, including clnt_perror.
335 */
336 void
set_output()337 set_output()
338 {
339 if (!isatty(1)) {
340 if (access(logfile, W_OK)) {
341 (void) freopen("/dev/null", "w", stderr);
342 } else {
343 (void) freopen(logfile, "a", stderr);
344 logging = TRUE;
345 }
346 }
347 }
348 /*
349 * This constructs a logging record.
350 */
351 void
logprintf(arg1,arg2,arg3,arg4,arg5,arg6,arg7)352 logprintf(arg1, arg2, arg3, arg4, arg5, arg6, arg7)
353 /*VARARGS*/
354 {
355 struct timeval t;
356
357 fseek(stderr, 0, 2);
358 if (logging) {
359 (void) gettimeofday(&t, NULL);
360 (void) fprintf(stderr, "%19.19s: ", ctime(&t.tv_sec));
361 }
362 (void) fprintf(stderr, (char *)arg1, arg2, arg3, arg4, arg5,
363 arg6, arg7);
364 fflush(stderr);
365 }
366
367 /*
368 * This does the command line argument processing.
369 */
370 void
get_command_line_args(argc,argv)371 get_command_line_args(argc, argv)
372 int argc;
373 char **argv;
374
375 {
376 argv++;
377
378 if (argc < 2) {
379 logprintf(err_usage);
380 xfr_exit(YPPUSH_BADARGS);
381 }
382
383 while (--argc) {
384
385 if ((*argv)[0] == '-') {
386
387 switch ((*argv)[1]) {
388
389 case 'f': {
390 force = TRUE;
391 argv++;
392 break;
393 }
394
395 case 'D': {
396 debug = TRUE;
397 argv++;
398 break;
399 }
400
401 case 'T': {
402 treepush = TRUE;
403 argv++;
404 break;
405 }
406 case 'P': {
407 check_count = TRUE;
408 argv++;
409 break;
410 }
411 case 'W': {
412 defwrite = FALSE;
413 argv++;
414 break;
415 }
416 case 'c': {
417 send_clear = FALSE;
418 argv++;
419 break;
420 }
421
422 case 'h': {
423
424 if (argc > 1) {
425 argv++;
426 argc--;
427 master = *argv;
428 argv++;
429
430 if (strlen(master) > 256) {
431 logprintf(
432 err_bad_args,
433 err_bad_hostname);
434 xfr_exit(YPPUSH_BADARGS);
435 }
436
437 } else {
438 logprintf(err_usage);
439 xfr_exit(YPPUSH_BADARGS);
440 }
441
442 break;
443 }
444
445 case 'd':
446 if (argc > 1) {
447 argv++;
448 argc--;
449 domain = *argv;
450 argv++;
451
452 if (strlen(domain) > YPMAXDOMAIN) {
453 logprintf(
454 err_bad_args,
455 err_bad_domainname);
456 xfr_exit(YPPUSH_BADARGS);
457 }
458
459 } else {
460 logprintf(err_usage);
461 xfr_exit(YPPUSH_BADARGS);
462 }
463 break;
464
465 case 's':
466 if (argc > 1) {
467 argv++;
468 argc--;
469 source = *argv;
470 argv++;
471
472 if (strlen(source) > YPMAXDOMAIN) {
473 logprintf(
474 err_bad_args,
475 err_bad_domainname);
476 xfr_exit(YPPUSH_BADARGS);
477 }
478
479 } else {
480 logprintf(err_usage);
481 xfr_exit(YPPUSH_BADARGS);
482 }
483 break;
484
485 case 'C':
486 if (argc > 3) {
487 callback = TRUE;
488 tid = *(++argv);
489 proto = *(++argv);
490 pushhost = *(++argv);
491 if (strlen(pushhost) > 256) {
492 logprintf(err_bad_args, err_bad_hostname);
493
494 xfr_exit(YPPUSH_BADARGS);
495 }
496 argc -= 3;
497 argv++;
498 } else {
499 logprintf(err_usage);
500 xfr_exit(YPPUSH_BADARGS);
501 }
502 break;
503
504 case 'b': {
505 interdomain_map = TRUE;
506 interdomain_value = "";
507 interdomain_sz = 0;
508 argv++;
509 break;
510 }
511
512
513 default: {
514 logprintf(err_usage);
515 xfr_exit(YPPUSH_BADARGS);
516 }
517
518 }
519
520 } else {
521
522 if (!map) {
523 map = *argv;
524 argv++;
525
526 if (strlen(map) > YPMAXMAP) {
527 logprintf(err_bad_args,
528 err_bad_mapname);
529 xfr_exit(YPPUSH_BADARGS);
530 }
531
532 } else {
533 logprintf(err_usage);
534 xfr_exit(YPPUSH_BADARGS);
535 }
536 }
537 }
538
539 if (!map) {
540 logprintf(err_usage);
541 xfr_exit(YPPUSH_BADARGS);
542 }
543 }
544
545 /*
546 * This tries to get the master name for the named map, from any
547 * server's version, using the vanilla NIS client interface. If we get a
548 * name back, the global "master" gets pointed to it.
549 */
550 void
find_map_master()551 find_map_master()
552 {
553 int err;
554
555 if (err = __yp_master_rsvdport(source, map, &master)) {
556 logprintf("Can't get master of %s. Reason: %s.\n", map,
557 yperr_string(err));
558 }
559
560 yp_unbind(source);
561 }
562
563 #ifdef TREEPUSH
564 int
chk_treepush(name)565 chk_treepush(name)
566 char *name;
567 {
568 char inmap[256];
569 char inkey[256];
570 int inkeylen;
571 char *outval;
572 int outvallen;
573 int err;
574 outval = NULL;
575 inkey[0] = 0;
576 strcpy(inmap, "ypslaves.");
577 strcat(inmap, name);
578 gethostname(inkey, 256);
579 inkeylen = strlen(inkey);
580
581 err = yp_match(source, inmap, inkey, inkeylen, &outval, &outvallen);
582 yp_unbind(source);
583 return (err);
584 }
585 #endif
586
587 /*
588 * This sets up a udp connection to speak the correct program and version
589 * to a NIS server. vers is set to YPVERS, doesn't give a damn about
590 * YPOLDVERS.
591 */
592 bool
bind_to_server(host,pdomb,vers,status)593 bind_to_server(host, pdomb, vers, status)
594 char *host;
595 struct dom_binding *pdomb;
596 unsigned int *vers;
597 int *status;
598 {
599 if (ping_server(host, pdomb, YPVERS, status)) {
600 *vers = YPVERS;
601 return (TRUE);
602 } else
603 return (FALSE);
604 }
605
606 /*
607 * This sets up a UDP channel to a server which is assumed to speak an input
608 * version of YPPROG. The channel is tested by pinging the server. In all
609 * error cases except "Program Version Number Mismatch", the error is
610 * reported, and in all error cases, the client handle is destroyed and the
611 * socket associated with the channel is closed.
612 */
613 bool
ping_server(host,pdomb,vers,status)614 ping_server(host, pdomb, vers, status)
615 char *host;
616 struct dom_binding *pdomb;
617 unsigned int vers;
618 int *status;
619 {
620 enum clnt_stat rpc_stat;
621
622 if ((pdomb->dom_client = __yp_clnt_create_rsvdport(host, YPPROG, vers,
623 0, 0, 0)) != 0) {
624
625 /*
626 * if we are on a c2 system, we should only accept data
627 * from a server which is on a reserved port.
628 */
629 /*
630 * NUKE this for 5.0DR.
631 *
632 * if (issecure() &&
633 * (pdomb->dom_server_addr.sin_family != AF_INET ||
634 * pdomb->dom_server_addr.sin_port >= IPPORT_RESERVED)) {
635 * clnt_destroy(pdomb->dom_client);
636 * close(pdomb->dom_socket);
637 * (void) logprintf("bind_to_server: \
638 * server is not using a privileged port\n");
639 * *status = YPPUSH_YPERR;
640 * return (FALSE);
641 * }
642 */
643
644 rpc_stat = clnt_call(pdomb->dom_client, YPBINDPROC_NULL,
645 xdr_void, 0, xdr_void, 0, udp_timeout);
646
647 if (rpc_stat == RPC_SUCCESS) {
648 return (TRUE);
649 } else {
650 clnt_destroy(pdomb->dom_client);
651 if (rpc_stat != RPC_PROGVERSMISMATCH) {
652 (void) clnt_perror(pdomb->dom_client,
653 "ypxfr: bind_to_server clnt_call error");
654 }
655
656 *status = YPPUSH_RPC;
657 return (FALSE);
658 }
659 } else {
660 logprintf("bind_to_server __clnt_create_rsvd error");
661 (void) clnt_pcreateerror("");
662 fflush(stderr);
663 *status = YPPUSH_RPC;
664 return (FALSE);
665 }
666 }
667
668 /*
669 * This gets values for the YP_LAST_MODIFIED and YP_MASTER_NAME keys from the
670 * master server's version of the map. Values are held in static variables
671 * here. In the success cases, global pointer variables are set to point at
672 * the local statics.
673 */
674 bool
get_private_recs(pushstat)675 get_private_recs(pushstat)
676 int *pushstat;
677 {
678 static char anumber[20];
679 static unsigned number;
680 static char name[YPMAXPEER + 1];
681 int status;
682
683 status = 0;
684
685 if (get_order(anumber, &number, &status)) {
686 master_version = &number;
687 master_ascii_version = anumber;
688 if (debug) fprintf(stderr,
689 "ypxfr: Master Version is %s\n", master_ascii_version);
690 } else {
691
692 if (status != 0) {
693 *pushstat = status;
694 if (debug) fprintf(stderr,
695 "ypxfr: Couldn't get map's master version number, \
696 status was %d\n", status);
697 return (FALSE);
698 }
699 }
700
701 if (get_master_name(name, &status)) {
702 master_name = name;
703 if (debug) fprintf(stderr,
704 "ypxfr: Maps master is '%s'\n", master_name);
705 } else {
706
707 if (status != 0) {
708 *pushstat = status;
709 if (debug) fprintf(stderr,
710 "ypxfr: Couldn't get map's master name, status was %d\n",
711 status);
712 return (FALSE);
713 }
714 master_name = master;
715 }
716
717 if (debug)
718 fprintf(stderr,
719 "ypxfr: Getting private records from master.\n");
720 if (get_misc_recs(&status)) {
721 if (debug)
722 fprintf(stderr,
723 "ypxfr: Masters map %s secure and %s an interdomain map.\n",
724 (secure_map) ? "is" : "is not",
725 (interdomain_map) ? "is" : "is not");
726 } else {
727 if (status != 0) {
728 *pushstat = status;
729 if (debug)
730 fprintf(stderr,
731 "ypxfr: Couldn't get state of secure and interdomain flags in map.\n");
732 return (FALSE);
733 }
734 }
735
736 return (TRUE);
737 }
738
739 /*
740 * This gets the map's order number from the master server
741 */
742 bool
get_order(an,n,pushstat)743 get_order(an, n, pushstat)
744 char *an;
745 unsigned *n;
746 int *pushstat;
747 {
748 if (master_prog_vers == YPVERS) {
749 return (get_v2order(an, n, pushstat));
750 } else
751 return (FALSE);
752 }
753
754 bool
get_v2order(an,n,pushstat)755 get_v2order(an, n, pushstat)
756 char *an;
757 unsigned *n;
758 int *pushstat;
759 {
760 struct ypreq_nokey req;
761 struct ypresp_order resp;
762 int retval;
763
764 req.domain = source;
765 req.map = map;
766
767 /*
768 * Get the map''s order number, null-terminate it and store it,
769 * and convert it to binary and store it again.
770 */
771 retval = FALSE;
772
773 if ((enum clnt_stat) clnt_call(master_server.dom_client,
774 YPPROC_ORDER, (xdrproc_t)xdr_ypreq_nokey, (char *)&req,
775 (xdrproc_t)xdr_ypresp_order, (char *)&resp,
776 udp_timeout) == RPC_SUCCESS) {
777
778 if (resp.status == YP_TRUE) {
779 sprintf(an, "%d", resp.ordernum);
780 *n = resp.ordernum;
781 retval = TRUE;
782 } else if (resp.status != YP_BADDB) {
783 *pushstat = ypprot_err(resp.status);
784
785 if (!logging) {
786 logprintf(
787 "(info) Can't get order number from ypserv at %s. Reason: %s.\n",
788 master, yperr_string(
789 ypprot_err(resp.status)));
790 }
791 }
792
793 CLNT_FREERES(master_server.dom_client,
794 (xdrproc_t)xdr_ypresp_order,
795 (char *)&resp);
796 } else {
797 *pushstat = YPPUSH_RPC;
798 logprintf("ypxfr(get_v2order) RPC call to %s failed", master);
799 clnt_perror(master_server.dom_client, "");
800 }
801
802 return (retval);
803 }
804
805 /*
806 * Pick up the state of the YP_SECURE and YP_INTERDOMAIN records from the
807 * master. Only works on 4.0 V2 masters that will match a YP_ private key
808 * when asked to explicitly.
809 */
810 bool
get_misc_recs(pushstat)811 get_misc_recs(pushstat)
812 int *pushstat;
813 {
814 struct ypreq_key req;
815 struct ypresp_val resp;
816 int retval;
817
818 req.domain = source;
819 req.map = map;
820 req.keydat.dptr = yp_secure;
821 req.keydat.dsize = yp_secure_sz;
822
823 resp.valdat.dptr = NULL;
824 resp.valdat.dsize = 0;
825
826 /*
827 * Get the value of the IS_SECURE key in the map.
828 */
829 retval = FALSE;
830
831 if (debug)
832 fprintf(stderr, "ypxfr: Checking masters secure key.\n");
833 if ((enum clnt_stat) clnt_call(master_server.dom_client,
834 YPPROC_MATCH, (xdrproc_t)xdr_ypreq_key, (char *)&req,
835 (xdrproc_t)xdr_ypresp_val, (char *)&resp,
836 udp_timeout) == RPC_SUCCESS) {
837 if (resp.status == YP_TRUE) {
838 if (debug)
839 fprintf(stderr, "ypxfr: SECURE\n");
840 secure_map = TRUE;
841 retval = TRUE;
842 } else if ((resp.status != YP_NOKEY) &&
843 (resp.status != YP_VERS) &&
844 (resp.status != YP_NOMORE)) {
845 *pushstat = ypprot_err(resp.status);
846
847 if (!logging) {
848 logprintf(
849 "(info) Can't get secure flag from ypserv at %s. Reason: %s.\n",
850 master, yperr_string(
851 ypprot_err(resp.status)));
852 }
853 }
854
855 CLNT_FREERES(master_server.dom_client,
856 (xdrproc_t)xdr_ypresp_val,
857 (char *)&resp);
858 } else {
859 *pushstat = YPPUSH_RPC;
860 logprintf("ypxfr(get_misc_recs) RPC call to %s failed", master);
861 clnt_perror(master_server.dom_client, "");
862 }
863
864 if (debug)
865 fprintf(stderr, "ypxfr: Checking masters INTERDOMAIN key.\n");
866 req.keydat.dptr = yp_interdomain;
867 req.keydat.dsize = yp_interdomain_sz;
868
869 resp.valdat.dptr = NULL;
870 resp.valdat.dsize = 0;
871
872 /*
873 * Get the value of the INTERDOMAIN key in the map.
874 */
875
876 if ((enum clnt_stat) clnt_call(master_server.dom_client,
877 YPPROC_MATCH, (xdrproc_t)xdr_ypreq_key, (char *)&req,
878 (xdrproc_t)xdr_ypresp_val, (char *)&resp,
879 udp_timeout) == RPC_SUCCESS) {
880 if (resp.status == YP_TRUE) {
881 if (debug)
882 fprintf(stderr, "ypxfr: INTERDOMAIN\n");
883 interdomain_map = TRUE;
884 interdomain_value = (char *)malloc(resp.valdat.dsize+1);
885 (void) memmove(interdomain_value, resp.valdat.dptr,
886 resp.valdat.dsize);
887 *(interdomain_value+resp.valdat.dsize) = '\0';
888 interdomain_sz = resp.valdat.dsize;
889 retval = TRUE;
890 } else if ((resp.status != YP_NOKEY) &&
891 (resp.status != YP_VERS) &&
892 (resp.status != YP_NOMORE)) {
893 *pushstat = ypprot_err(resp.status);
894
895 if (!logging) {
896 logprintf(
897 "(info) Can't get interdomain flag from ypserv at %s. Reason: %s.\n",
898 master, yperr_string(
899 ypprot_err(resp.status)));
900 }
901 }
902
903 CLNT_FREERES(master_server.dom_client,
904 (xdrproc_t)xdr_ypresp_val,
905 (char *)&resp);
906 } else {
907 *pushstat = YPPUSH_RPC;
908 logprintf("ypxfr(get_misc_recs) RPC call to %s failed", master);
909 clnt_perror(master_server.dom_client, "");
910 }
911
912
913 return (retval);
914 }
915
916 /*
917 * This gets the map's master name from the master server
918 */
919 bool
get_master_name(name,pushstat)920 get_master_name(name, pushstat)
921 char *name;
922 int *pushstat;
923 {
924 if (master_prog_vers == YPVERS) {
925 return (get_v2master_name(name, pushstat));
926 } else
927 return (FALSE);
928 }
929
930 bool
get_v2master_name(name,pushstat)931 get_v2master_name(name, pushstat)
932 char *name;
933 int *pushstat;
934 {
935 struct ypreq_nokey req;
936 struct ypresp_master resp;
937 int retval;
938
939 req.domain = source;
940 req.map = map;
941 resp.master = NULL;
942 retval = FALSE;
943
944 if ((enum clnt_stat) clnt_call(master_server.dom_client,
945 YPPROC_MASTER, (xdrproc_t)xdr_ypreq_nokey, (char *)&req,
946 (xdrproc_t)xdr_ypresp_master, (char *)&resp,
947 udp_timeout) == RPC_SUCCESS) {
948
949 if (resp.status == YP_TRUE) {
950 strcpy(name, resp.master);
951 retval = TRUE;
952 } else if (resp.status != YP_BADDB) {
953 *pushstat = ypprot_err(resp.status);
954
955 if (!logging) {
956 logprintf(
957 "(info) Can't get master name from ypserv at %s. Reason: %s.\n",
958 master, yperr_string(
959 ypprot_err(resp.status)));
960 }
961 }
962
963 CLNT_FREERES(master_server.dom_client,
964 (xdrproc_t)xdr_ypresp_master,
965 (char *)&resp);
966 } else {
967 *pushstat = YPPUSH_RPC;
968 logprintf(
969 "ypxfr(get_v2master_name) RPC call to %s failed", master);
970 clnt_perror(master_server.dom_client, "");
971 }
972
973 return (retval);
974 }
975
976 /*
977 * This does the work of transferring the map.
978 */
979 bool
move_map(pushstat)980 move_map(pushstat)
981 int *pushstat;
982 {
983 unsigned local_version;
984 char map_name[MAXNAMLEN + 1];
985 char tmp_name[MAXNAMLEN + 1];
986 char bkup_name[MAXNAMLEN + 1];
987 char an[11];
988 unsigned n;
989 datum key;
990 datum val;
991 int hgstatus;
992
993 mkfilename(map_name);
994
995 if (!force) {
996 local_version = get_local_version(map_name);
997 if (debug) fprintf(stderr,
998 "ypxfr: Local version of map '%s' is %d\n",
999 map_name, local_version);
1000
1001 if (local_version >= *master_version) {
1002 logprintf(
1003 "Map %s at %s is not more recent than local.\n",
1004 map, master);
1005 *pushstat = YPPUSH_AGE;
1006 return (FALSE);
1007 }
1008 }
1009
1010 mk_tmpname(yptempname_prefix, tmp_name);
1011
1012 if (!new_mapfiles(tmp_name)) {
1013 logprintf(
1014 "Can't create temp map %s.\n", tmp_name);
1015 *pushstat = YPPUSH_FILE;
1016 return (FALSE);
1017 }
1018
1019 if ((hgstatus = ypxfrd_getdbm(tmp_name, master, source, map)) < 0)
1020 {
1021 logprintf(
1022 "(info) %s %s %s ypxfrd getdbm failed (reason = %d) -- using ypxfr\n",
1023 master, domain, map, hgstatus);
1024
1025 db = dbm_open(tmp_name, O_RDWR + O_CREAT + O_TRUNC, 0644);
1026 if (db == NULL) {
1027 logprintf(
1028 "Can't dbm init temp map %s.\n", tmp_name);
1029 del_mapfiles(tmp_name);
1030 *pushstat = YPPUSH_DBM;
1031 return (FALSE);
1032 }
1033 if (defwrite) dbm_setdefwrite(db);
1034
1035 if (!get_map(tmp_name, pushstat)) {
1036 del_mapfiles(tmp_name);
1037 return (FALSE);
1038 }
1039
1040 if (!add_private_entries(tmp_name)) {
1041 del_mapfiles(tmp_name);
1042 *pushstat = YPPUSH_DBM;
1043 return (FALSE);
1044 }
1045
1046 /*
1047 * Decide whether the map just transferred is a secure map.
1048 * If we already know the local version was secure, we do not
1049 * need to check this version.
1050 */
1051 if (!secure_map) {
1052 key.dptr = yp_secure;
1053 key.dsize = yp_secure_sz;
1054 val = dbm_fetch(db, key);
1055 if (val.dptr != NULL) {
1056 secure_map = TRUE;
1057 }
1058 }
1059
1060 if (dbm_close_status(db) < 0) {
1061 logprintf(
1062 "Can't do dbm close operation on temp map %s.\n",
1063 tmp_name);
1064 del_mapfiles(tmp_name);
1065 *pushstat = YPPUSH_DBM;
1066 return (FALSE);
1067 }
1068
1069 if (!get_order(an, &n, pushstat)) {
1070 return (FALSE);
1071 }
1072 if (n != *master_version) {
1073 logprintf(
1074 "Version skew at %s while transferring map %s.\n",
1075 master, map);
1076 del_mapfiles(tmp_name);
1077 *pushstat = YPPUSH_SKEW;
1078 return (FALSE);
1079 }
1080
1081 if (check_count)
1082 if (!count_mismatch(tmp_name, entry_count)) {
1083 del_mapfiles(tmp_name);
1084 *pushstat = YPPUSH_DBM;
1085 return (FALSE);
1086 }
1087 } else {
1088 /* touch up the map */
1089 db = dbm_open(tmp_name, 2, 0644);
1090 if (db == NULL) {
1091 logprintf(
1092 "Can't dbm init temp map %s.\n", tmp_name);
1093 del_mapfiles(tmp_name);
1094 *pushstat = YPPUSH_DBM;
1095 return (FALSE);
1096 }
1097
1098
1099 if (!add_private_entries(tmp_name)) {
1100 del_mapfiles(tmp_name);
1101 *pushstat = YPPUSH_DBM;
1102 return (FALSE);
1103 }
1104
1105 /*
1106 * Decide whether the map just transferred is a secure map.
1107 * If we already know the local version was secure, we do not
1108 * need to check this version.
1109 */
1110 if (!secure_map) {
1111 key.dptr = yp_secure;
1112 key.dsize = yp_secure_sz;
1113 val = dbm_fetch(db, key);
1114 if (val.dptr != NULL) {
1115 secure_map = TRUE;
1116 }
1117 }
1118
1119 if (dbm_close_status(db) < 0) {
1120 logprintf(
1121 "Can't do dbm close operation on temp map %s.\n",
1122 tmp_name);
1123 del_mapfiles(tmp_name);
1124 *pushstat = YPPUSH_DBM;
1125 return (FALSE);
1126 }
1127
1128 }
1129
1130 if (lock_map(map_name) == 0) {
1131 del_mapfiles(tmp_name);
1132 logprintf("Lock error on %s\n", map_name);
1133 *pushstat = YPPUSH_FILE;
1134 return (FALSE);
1135 }
1136 if (!check_map_existence(map_name)) {
1137
1138 if (!rename_map(tmp_name, map_name, secure_map)) {
1139 del_mapfiles(tmp_name);
1140 logprintf(
1141 "Rename error: couldn't mv %s to %s.\n",
1142 tmp_name, map_name);
1143 *pushstat = YPPUSH_FILE;
1144 unlock_map(map_name);
1145 return (FALSE);
1146 }
1147
1148 } else {
1149 mk_tmpname(ypbkupname_prefix, bkup_name);
1150
1151 if (!rename_map(map_name, bkup_name, secure_map)) {
1152 (void) rename_map(bkup_name, map_name, secure_map);
1153 logprintf(
1154 "Rename error: check that old %s is still intact.\n",
1155 map_name);
1156 del_mapfiles(tmp_name);
1157 *pushstat = YPPUSH_FILE;
1158 unlock_map(map_name);
1159 return (FALSE);
1160 }
1161
1162 if (rename_map(tmp_name, map_name, secure_map)) {
1163 del_mapfiles(bkup_name);
1164 } else {
1165 del_mapfiles(tmp_name);
1166 (void) rename_map(bkup_name, map_name, secure_map);
1167 logprintf(
1168 "Rename error: check that old %s is still intact.\n",
1169 map_name);
1170 *pushstat = YPPUSH_FILE;
1171 unlock_map(map_name);
1172 return (FALSE);
1173 }
1174 }
1175 if (unlock_map(map_name) == 0)
1176 return (FALSE);
1177
1178 return (TRUE);
1179 }
1180
1181 /*
1182 * This tries to get the order number out of the local version of the map.
1183 * If the attempt fails for any version, the function will return "0"
1184 */
1185 unsigned
get_local_version(name)1186 get_local_version(name)
1187 char *name;
1188 {
1189 datum key;
1190 datum val;
1191 char number[11];
1192 DBM *db;
1193
1194 if (!check_map_existence(name)) {
1195 return (0);
1196 }
1197 if (debug) fprintf(stderr,
1198 "ypxfr: Map does exist, checking version now.\n");
1199
1200 if ((db = dbm_open(name, 0, 0)) == 0) {
1201 return (0);
1202 }
1203
1204 key.dptr = yp_last_modified;
1205 key.dsize = yp_last_modified_sz;
1206 val = dbm_fetch(db, key);
1207 if (!val.dptr) { /* Check to see if dptr is NULL */
1208 return (0);
1209 }
1210 if (val.dsize == 0 || val.dsize > 10) {
1211 return (0);
1212 }
1213 /* Now save this value while we have it available */
1214 (void) memmove(number, val.dptr, val.dsize);
1215 number[val.dsize] = '\0';
1216
1217 /*
1218 * Now check to see if it is 'secure'. If we haven't already
1219 * determined that it is secure in get_private_recs() then we check
1220 * the local map here.
1221 */
1222 if (!secure_map) {
1223 key.dptr = yp_secure;
1224 key.dsize = yp_secure_sz;
1225 val = dbm_fetch(db, key);
1226 secure_map = (val.dptr != NULL);
1227 }
1228
1229 /*
1230 * Now check to see if interdomain requests are made of the local
1231 * map. Keep the value around if they are.
1232 */
1233 if (!interdomain_map) {
1234 key.dptr = yp_interdomain;
1235 key.dsize = yp_interdomain_sz;
1236 val = dbm_fetch(db, key);
1237 if (interdomain_map = (val.dptr != NULL)) {
1238 interdomain_value = (char *)malloc(val.dsize+1);
1239 (void) memmove(interdomain_value, val.dptr, val.dsize);
1240 *(interdomain_value+val.dsize) = '\0';
1241 interdomain_sz = val.dsize;
1242 }
1243 }
1244
1245 /* finish up */
1246 (void) dbm_close_status(db);
1247
1248 return ((unsigned)atoi(number));
1249 }
1250
1251 /*
1252 * This constructs a file name for a map, minus its dbm_dir
1253 * or dbm_pag extensions
1254 */
1255 void
mkfilename(ppath)1256 mkfilename(ppath)
1257 char *ppath;
1258 {
1259 bool_t yptol_mode;
1260 int len;
1261
1262 /* Work out if we are in yptol mode */
1263 yptol_mode = is_yptol_mode();
1264
1265 len = strlen(domain) + strlen(map) + strlen(ypdbpath) + 3;
1266 if (yptol_mode)
1267 len += strlen(NTOL_PREFIX);
1268
1269 if (len > (MAXNAMLEN + 1)) {
1270 logprintf("Map name string too long.\n");
1271 }
1272
1273 (void) strcpy(ppath, ypdbpath);
1274 (void) strcat(ppath, "/");
1275 (void) strcat(ppath, domain);
1276 (void) strcat(ppath, "/");
1277 if (yptol_mode)
1278 (void) strcat(ppath, NTOL_PREFIX);
1279 (void) strcat(ppath, map);
1280 }
1281
1282 /*
1283 * This returns a temporary name for a map transfer minus its dbm_dir or
1284 * dbm_pag extensions.
1285 */
1286 void
mk_tmpname(prefix,xfr_name)1287 mk_tmpname(prefix, xfr_name)
1288 char *prefix;
1289 char *xfr_name;
1290 {
1291 char xfr_anumber[10];
1292 long xfr_number;
1293
1294 if (!xfr_name) {
1295 return;
1296 }
1297
1298 xfr_number = getpid();
1299 (void) sprintf(xfr_anumber, "%d", xfr_number);
1300
1301 (void) strcpy(xfr_name, ypdbpath);
1302 (void) strcat(xfr_name, "/");
1303 (void) strcat(xfr_name, domain);
1304 (void) strcat(xfr_name, "/");
1305 (void) strcat(xfr_name, prefix);
1306 (void) strcat(xfr_name, map);
1307 (void) strcat(xfr_name, ".");
1308 (void) strcat(xfr_name, xfr_anumber);
1309 }
1310
1311 /*
1312 * This deletes the .pag and .dir files which implement a map.
1313 *
1314 * Note: No error checking is done here for a garbage input file name or for
1315 * failed unlink operations.
1316 */
1317 void
del_mapfiles(basename)1318 del_mapfiles(basename)
1319 char *basename;
1320 {
1321 char dbfilename[MAXNAMLEN + 1];
1322
1323 if (!basename) {
1324 return;
1325 }
1326
1327 strcpy(dbfilename, basename);
1328 strcat(dbfilename, dbm_pag);
1329 unlink(dbfilename);
1330 strcpy(dbfilename, basename);
1331 strcat(dbfilename, dbm_dir);
1332 unlink(dbfilename);
1333 }
1334
1335 /*
1336 * This creates <pname>.dir and <pname>.pag
1337 */
1338 bool
new_mapfiles(pname)1339 new_mapfiles(pname)
1340 char *pname;
1341 {
1342 char dbfile[MAXNAMLEN + 1];
1343 int f;
1344 int len;
1345
1346 if (!pname || ((len = strlen(pname)) == 0) ||
1347 (len + 5) > (MAXNAMLEN + 1)) {
1348 return (FALSE);
1349 }
1350
1351 errno = 0;
1352 (void) strcpy(dbfile, pname);
1353 (void) strcat(dbfile, dbm_dir);
1354
1355 if ((f = open(dbfile, (O_WRONLY | O_CREAT | O_TRUNC), 0600)) >= 0) {
1356 (void) close(f);
1357 (void) strcpy(dbfile, pname);
1358 (void) strcat(dbfile, dbm_pag);
1359
1360 if ((f = open(dbfile, (O_WRONLY | O_CREAT | O_TRUNC),
1361 0600)) >= 0) {
1362 (void) close(f);
1363 return (TRUE);
1364 } else {
1365 return (FALSE);
1366 }
1367
1368 } else {
1369 return (FALSE);
1370 }
1371 }
1372
1373 int
count_callback(status)1374 count_callback(status)
1375 int status;
1376 {
1377 if (status != YP_TRUE) {
1378
1379 if (status != YP_NOMORE) {
1380 logprintf(
1381 "Error from ypserv on %s (ypall_callback) = %s.\n",
1382 master, yperr_string(ypprot_err(status)));
1383 }
1384
1385 return (TRUE);
1386 }
1387
1388 entry_count++;
1389 return (FALSE);
1390 }
1391
1392 /*
1393 * This counts the entries in the dbm file after the transfer to
1394 * make sure that the dbm file was built correctly.
1395 * Returns TRUE if everything is OK, FALSE if they mismatch.
1396 */
1397 int
count_mismatch(pname,oldcount)1398 count_mismatch(pname, oldcount)
1399 char *pname;
1400 int oldcount;
1401 {
1402 datum key;
1403 DBM *db;
1404 #ifdef REALLY_PARANOID
1405 struct ypall_callback cbinfo;
1406 struct ypreq_nokey allreq;
1407 enum clnt_stat s;
1408 struct dom_binding domb;
1409 datum value;
1410 #endif /* REALLY_PARANOID */
1411
1412 entry_count = 0;
1413 db = dbm_open(pname, 0, 0);
1414 if (db) {
1415 for (key = dbm_firstkey(db);
1416 key.dptr != NULL; key = dbm_nextkey(db))
1417 entry_count++;
1418 dbm_close_status(db);
1419 }
1420
1421 if (oldcount != entry_count) {
1422 logprintf(
1423 "*** Count mismatch in dbm file %s: old=%d, new=%d ***\n",
1424 map, oldcount, entry_count);
1425 return (FALSE);
1426 }
1427
1428 #ifdef REALLY_PARANOID
1429
1430 if ((domb.dom_client = __yp_clnt_create_rsvdport(master, YPPROG,
1431 master_prog_vers,
1432 "tcp6", 0, 0)) == 0 &&
1433 (domb.dom_client = __yp_clnt_create_rsvdport(master, YPPROG,
1434 master_prog_vers,
1435 "tcp", 0, 0)) == 0) {
1436 clnt_pcreateerror("ypxfr (mismatch) - TCP channel "
1437 "create failure");
1438 return (FALSE);
1439 }
1440
1441 if (master_prog_vers == YPVERS) {
1442 int tmpstat;
1443
1444 allreq.domain = source;
1445 allreq.map = map;
1446 cbinfo.foreach = count_callback;
1447 tmpstat = 0;
1448 cbinfo.data = (char *)&tmpstat;
1449
1450 entry_count = 0;
1451 s = clnt_call(domb.dom_client, YPPROC_ALL, xdr_ypreq_nokey,
1452 &allreq, xdr_ypall, &cbinfo, tcp_timeout);
1453
1454 if (tmpstat == 0) {
1455 if (s == RPC_SUCCESS) {
1456 } else {
1457 clnt_perror(domb.dom_client,
1458 "ypxfr (get_map/all) - RPC clnt_call (TCP) failure");
1459 return (FALSE);
1460 }
1461
1462 } else {
1463 return (FALSE);
1464 }
1465
1466 } else {
1467 logprintf("Wrong version number!\n");
1468 return (FALSE);
1469 }
1470 clnt_destroy(domb.dom_client);
1471 close(domb.dom_socket);
1472 entry_count += 2; /* add in YP_entries */
1473 if (oldcount != entry_count) {
1474 logprintf(
1475 "*** Count mismatch after enumerate %s: old=%d, new=%d ***\n",
1476 map, oldcount, entry_count);
1477 return (FALSE);
1478 }
1479 #endif /* REALLY_PARANOID */
1480
1481 return (TRUE);
1482 }
1483
1484 /*
1485 * This sets up a TCP connection to the master server, and either gets
1486 * ypall_callback to do all the work of writing it to the local dbm file
1487 * (if the ypserv is current version), or does it itself for an old ypserv.
1488 */
1489 bool
get_map(pname,pushstat)1490 get_map(pname, pushstat)
1491 char *pname;
1492 int *pushstat;
1493 {
1494 struct dom_binding domb;
1495 enum clnt_stat s;
1496 struct ypreq_nokey allreq;
1497 struct ypall_callback cbinfo;
1498 bool retval = FALSE;
1499 int tmpstat;
1500 int recvsiz = 24 * 1024;
1501 struct netconfig *nconf;
1502 int fd;
1503 struct netbuf *svcaddr;
1504 char *netid[] = { "tcp6", "tcp" };
1505 int i, lastnetid = (sizeof (netid)/sizeof (netid[0])) - 1;
1506
1507 svcaddr = (struct netbuf *)calloc(1, sizeof (struct netbuf));
1508 if (! svcaddr)
1509 return (FALSE);
1510 svcaddr->maxlen = 32;
1511 svcaddr->len = 32;
1512 svcaddr->buf = (char *)malloc(32);
1513 if (! svcaddr->buf) {
1514 free(svcaddr);
1515 return (FALSE);
1516 }
1517
1518 for (i = 0; i <= lastnetid; i++) {
1519 fd = RPC_ANYFD;
1520 if ((nconf = getnetconfigent(netid[i])) == NULL) {
1521 if (i != lastnetid)
1522 continue;
1523 logprintf("ypxfr: tcp transport not supported\n");
1524 free(svcaddr->buf);
1525 free(svcaddr);
1526 return (FALSE);
1527 }
1528 if (rpcb_getaddr(YPPROG, master_prog_vers, nconf, svcaddr,
1529 master) == FALSE) {
1530 freenetconfigent(nconf);
1531 if (i != lastnetid)
1532 continue;
1533 logprintf("ypxfr: could not get %s address\n", master);
1534 free(svcaddr->buf);
1535 free(svcaddr);
1536 return (FALSE);
1537 }
1538 if ((domb.dom_client = __nis_clnt_create(fd, nconf, 0, svcaddr,
1539 0, YPPROG, master_prog_vers, recvsiz, 0)) == 0) {
1540 freenetconfigent(nconf);
1541 if (i != lastnetid)
1542 continue;
1543 clnt_pcreateerror(
1544 "ypxfr (get_map) - TCP channel create failure");
1545 *pushstat = YPPUSH_RPC;
1546 free(svcaddr->buf);
1547 free(svcaddr);
1548 return (FALSE);
1549 }
1550 break;
1551 }
1552
1553 entry_count = 0;
1554 if (master_prog_vers == YPVERS) {
1555 allreq.domain = source;
1556 allreq.map = map;
1557 cbinfo.foreach = ypall_callback;
1558 tmpstat = 0;
1559 cbinfo.data = (char *)&tmpstat;
1560
1561 s = clnt_call(domb.dom_client, YPPROC_ALL,
1562 (xdrproc_t)xdr_ypreq_nokey,
1563 (char *)&allreq, (xdrproc_t)xdr_ypall, (char *)&cbinfo,
1564 tcp_timeout);
1565
1566 if (tmpstat == 0) {
1567
1568 if (s == RPC_SUCCESS) {
1569 retval = TRUE;
1570 } else {
1571 clnt_perror(domb.dom_client,
1572 "ypxfr (get_map/all) - RPC clnt_call (TCP) failure");
1573 *pushstat = YPPUSH_RPC;
1574 }
1575
1576 } else {
1577 *pushstat = tmpstat;
1578 }
1579
1580 } else
1581 retval = FALSE; /* barf again at YPOLDVERS */
1582 cleanup:
1583 clnt_destroy(domb.dom_client);
1584 return (retval);
1585 }
1586
1587 /*
1588 * This sticks each key-value pair into the current map. It returns FALSE as
1589 * long as it wants to keep getting called back, and TRUE on error conditions
1590 * and "No more k-v pairs".
1591 */
1592 int
ypall_callback(status,key,kl,val,vl,pushstat)1593 ypall_callback(status, key, kl, val, vl, pushstat)
1594 int status;
1595 char *key;
1596 int kl;
1597 char *val;
1598 int vl;
1599 int *pushstat;
1600 {
1601 datum keydat;
1602 datum valdat;
1603 datum test;
1604
1605 if (status != YP_TRUE) {
1606
1607 if (status != YP_NOMORE) {
1608 logprintf(
1609 "Error from ypserv on %s (ypall_callback) = %s.\n",
1610 master, yperr_string(ypprot_err(status)));
1611 *pushstat = map_yperr_to_pusherr(status);
1612 }
1613
1614 return (TRUE);
1615 }
1616
1617 keydat.dptr = key;
1618 keydat.dsize = kl;
1619 valdat.dptr = val;
1620 valdat.dsize = vl;
1621 entry_count++;
1622 /* way too many fetches */
1623
1624 #ifdef PARANOID
1625 test = dbm_fetch(db, keydat);
1626 if (test.dptr != NULL) {
1627 logprintf("Duplicate key %s in map %s\n", key, map);
1628 *pushstat = YPPUSH_DBM;
1629 return (TRUE);
1630 }
1631 #endif /* PARANOID */
1632 if (dbm_store(db, keydat, valdat, 0) < 0) {
1633 logprintf(
1634 "Can't do dbm store into temp map %s.\n", map);
1635 *pushstat = YPPUSH_DBM;
1636 return (TRUE);
1637 }
1638 #ifdef PARANOID
1639 test = dbm_fetch(db, keydat);
1640 if (test.dptr == NULL) {
1641 logprintf("Key %s was not inserted into dbm file %s\n",
1642 key, map);
1643 *pushstat = YPPUSH_DBM;
1644 return (TRUE);
1645 }
1646 #endif /* PARANOID */
1647
1648 if (dbm_error(db)) {
1649 logprintf("Key %s dbm_error raised in file %s\n",
1650 key, map);
1651 *pushstat = YPPUSH_DBM;
1652 return (TRUE);
1653 }
1654 return (FALSE);
1655 }
1656
1657 /*
1658 * This maps a YP_xxxx error code into a YPPUSH_xxxx error code
1659 */
1660 int
map_yperr_to_pusherr(yperr)1661 map_yperr_to_pusherr(yperr)
1662 int yperr;
1663 {
1664 int reason;
1665
1666 switch (yperr) {
1667
1668 case YP_NOMORE:
1669 reason = YPPUSH_SUCC;
1670 break;
1671
1672 case YP_NOMAP:
1673 reason = YPPUSH_NOMAP;
1674 break;
1675
1676 case YP_NODOM:
1677 reason = YPPUSH_NODOM;
1678 break;
1679
1680 case YP_NOKEY:
1681 reason = YPPUSH_YPERR;
1682 break;
1683
1684 case YP_BADARGS:
1685 reason = YPPUSH_BADARGS;
1686 break;
1687
1688 case YP_BADDB:
1689 reason = YPPUSH_YPERR;
1690 break;
1691
1692 default:
1693 reason = YPPUSH_XFRERR;
1694 break;
1695 }
1696
1697 return (reason);
1698 }
1699
1700 /*
1701 * This writes the last-modified and master entries into the new dbm file
1702 */
1703 bool
add_private_entries(pname)1704 add_private_entries(pname)
1705 char *pname;
1706 {
1707 datum key;
1708 datum val;
1709
1710 if (!fake_master_version) {
1711 key.dptr = yp_last_modified;
1712 key.dsize = yp_last_modified_sz;
1713 val.dptr = master_ascii_version;
1714 val.dsize = strlen(master_ascii_version);
1715
1716 if (dbm_store(db, key, val, 1) < 0) {
1717 logprintf(
1718 "Can't do dbm store into temp map %s.\n",
1719 pname);
1720 return (FALSE);
1721 }
1722 entry_count++;
1723 }
1724
1725 if (master_name) {
1726 key.dptr = yp_master_name;
1727 key.dsize = yp_master_name_sz;
1728 val.dptr = master_name;
1729 val.dsize = strlen(master_name);
1730 if (dbm_store(db, key, val, 1) < 0) {
1731 logprintf(
1732 "Can't do dbm store into temp map %s.\n",
1733 pname);
1734 return (FALSE);
1735 }
1736 entry_count++;
1737 }
1738
1739 if (interdomain_map) {
1740 key.dptr = yp_interdomain;
1741 key.dsize = yp_interdomain_sz;
1742 val.dptr = interdomain_value;
1743 val.dsize = interdomain_sz;
1744 if (dbm_store(db, key, val, 1) < 0) {
1745 logprintf(
1746 "Can't do dbm store into temp map %s.\n",
1747 pname);
1748 return (FALSE);
1749 }
1750 entry_count++;
1751 }
1752
1753 if (secure_map) {
1754 key.dptr = yp_secure;
1755 key.dsize = yp_secure_sz;
1756 val.dptr = yp_secure;
1757 val.dsize = yp_secure_sz;
1758 if (dbm_store(db, key, val, 1) < 0) {
1759 logprintf(
1760 "Can't do dbm store into temp map %s.\n",
1761 pname);
1762 return (FALSE);
1763 }
1764 entry_count++;
1765 }
1766
1767 return (TRUE);
1768 }
1769
1770
1771 /*
1772 * This sends a YPPROC_CLEAR message to the local ypserv process.
1773 */
1774 bool
send_ypclear(pushstat)1775 send_ypclear(pushstat)
1776 int *pushstat;
1777 {
1778 struct dom_binding domb;
1779 char local_host_name[256];
1780 unsigned int progvers;
1781 int status;
1782
1783 if (gethostname(local_host_name, 256)) {
1784 logprintf("Can't get local machine name.\n");
1785 *pushstat = YPPUSH_RSRC;
1786 return (FALSE);
1787 }
1788
1789 if (!bind_to_server(local_host_name, &domb,
1790 &progvers, &status)) {
1791 *pushstat = YPPUSH_CLEAR;
1792 return (FALSE);
1793 }
1794
1795 if ((enum clnt_stat) clnt_call(domb.dom_client,
1796 YPPROC_CLEAR, xdr_void, 0, xdr_void, 0,
1797 udp_timeout) != RPC_SUCCESS) {
1798 logprintf(
1799 "Can't send ypclear message to ypserv on the local machine.\n");
1800 xfr_exit(YPPUSH_CLEAR);
1801 }
1802
1803 return (TRUE);
1804 }
1805
1806 /*
1807 * This decides if send_callback has to get called, and does the process exit.
1808 */
1809 void
xfr_exit(status)1810 xfr_exit(status)
1811 int status;
1812 {
1813 if (callback) {
1814 send_callback(&status);
1815 }
1816
1817 if (status == YPPUSH_SUCC) {
1818 #ifdef TREEPUSH
1819 if (treepush) {
1820 if (debug)
1821 execlp("./yppush", "yppush", "-T", map, 0);
1822 execlp("/usr/etc/yp/yppush", "yppush", "-T", map, 0);
1823 perror("yppush");
1824 }
1825 #endif
1826 exit(0);
1827 } else {
1828 exit(1);
1829 }
1830 }
1831
1832 /*
1833 * This sets up a UDP connection to the yppush process which contacted our
1834 * parent ypserv, and sends him a status on the requested transfer.
1835 */
1836 void
send_callback(status)1837 send_callback(status)
1838 int *status;
1839 {
1840 struct yppushresp_xfr resp;
1841 struct dom_binding domb;
1842
1843 resp.transid = (unsigned long) atoi(tid);
1844 resp.status = (unsigned long) *status;
1845
1846 udp_timeout.tv_sec = CALLTIMEOUT;
1847
1848 if ((domb.dom_client = __yp_clnt_create_rsvdport(pushhost,
1849 (ulong_t)atoi(proto),
1850 YPPUSHVERS,
1851 0, 0, 0)) == NULL) {
1852 *status = YPPUSH_RPC;
1853 return;
1854 }
1855
1856 if ((enum clnt_stat) clnt_call(domb.dom_client,
1857 YPPUSHPROC_XFRRESP, (xdrproc_t)xdr_yppushresp_xfr,
1858 (char *)&resp, xdr_void, 0,
1859 udp_timeout) != RPC_SUCCESS) {
1860 *status = YPPUSH_RPC;
1861 return;
1862 }
1863 }
1864
1865 /*
1866 * FUNCTION: is_yptol_mode();
1867 *
1868 * DESCRIPTION: Determines if we should run in N2L or traditional mode based
1869 * on the presence of the N2L mapping file.
1870 *
1871 * This is a copy of a function from libnisdb. If more than this
1872 * one function become required it may be worth linking the
1873 * entire lib.
1874 *
1875 * INPUTS: Nothing
1876 *
1877 * OUTPUTS: TRUE = Run in N2L mode
1878 * FALSE = Run in traditional mode.
1879 */
1880 bool_t
is_yptol_mode()1881 is_yptol_mode()
1882 {
1883 struct stat filestat;
1884
1885 if (stat(NTOL_MAP_FILE, &filestat) != -1)
1886 return (TRUE);
1887
1888 return (FALSE);
1889 }
1890