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