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
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.
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]
22 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright (c) 2016 by Delphix. All rights reserved.
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 * Portions of this source code were derived from Berkeley
32 * under license from the Regents of the University of
37 * This is a user command which gets a NIS data base from some running
38 * server, and gets it to the local site by using the normal NIS client
39 * enumeration functions. The map is copied to a temp name, then the real
40 * map is removed and the temp map is moved to the real name. ypxfr then
41 * sends a "YPPROC_CLEAR" message to the local server to insure that it will
42 * not hold a removed map open, so serving an obsolete version.
44 * ypxfr [ -h <host> ] [ -d <domainname> ]
45 * [ -s <domainname> ] [-f] [-c] [-C tid prot name] map
47 * If the host is ommitted, ypxfr will attempt to discover the master by
48 * using normal NIS services. If it can't get the record, it will use
49 * the address of the callback, if specified. If the host is specified
50 * as an internet address, no NIS services need to be locally available.
52 * If the domain is not specified, the default domain of the local machine
55 * If the -f flag is used, the transfer will be done even if the master's
56 * copy is not newer than the local copy.
58 * The -c flag suppresses the YPPROC_CLEAR request to the local ypserv. It
59 * may be used if ypserv isn't currently running to suppress the error message.
61 * The -C flag is used to pass callback information to ypxfr when it is
62 * activated by ypserv. The callback information is used to send a
63 * yppushresp_xfr message with transaction id "tid" to a yppush process
64 * speaking a transient protocol number "prot". The yppush program is
65 * running on the host "name".
67 * The -s option is used to specify a source domain which may be
68 * different from the destination domain, for transfer of maps
69 * that are identical in different domains (e.g. services.byname)
81 #include <netconfig.h>
87 #include <rpcsvc/ypclnt.h>
88 #include <rpcsvc/yp_prot.h>
91 #include <rpcsvc/nis.h>
104 #define PARANOID 1 /* make sure maps have the right # entries */
106 #define CALLINTER_TRY 10 /* Seconds between callback tries */
107 #define CALLTIMEOUT CALLINTER_TRY*6 /* Total timeout for callback */
111 /* ypxfr never uses N2L mode */
112 bool_t yptol_mode
= FALSE
;
115 int treepush
= FALSE
;
123 char *pushhost
= NULL
;
125 * The name of the xfer peer as specified as a
126 * -h option, -C name option or from querying the NIS
128 struct dom_binding master_server
; /* To talk to above */
129 unsigned int master_prog_vers
; /* YPVERS (barfs at YPOLDVERS !) */
130 char *master_name
= NULL
; /* Map's master as contained in the map */
131 unsigned *master_version
= NULL
; /* Order number as contained in the map */
132 char *master_ascii_version
; /* ASCII order number as contained in the map */
133 bool fake_master_version
= FALSE
;
135 * TRUE only if there's no order number in
136 * the map, and the user specified -f
138 bool force
= FALSE
; /* TRUE iff user specified -f flag */
139 bool logging
= FALSE
; /* TRUE iff no tty, but log file exists */
140 bool check_count
= FALSE
; /* TRUE causes counts to be checked */
141 bool send_clear
= TRUE
; /* FALSE iff user specified -c flag */
142 bool callback
= FALSE
;
144 * TRUE iff -C flag set. tid, proto and name
145 * will be set to point to the command line args.
147 bool secure_map
= FALSE
; /* TRUE if there is yp_secure in the map */
148 bool interdomain_map
= FALSE
;
150 * TRUE if there is yp_interdomain in either
151 * the local or the master version of the map
153 int interdomain_sz
= 0; /* Size of the interdomain value */
154 #define UDPINTER_TRY 10 /* Seconds between tries for udp */
155 #define UDPTIMEOUT UDPINTER_TRY*4 /* Total timeout for udp */
156 #define CALLINTER_TRY 10 /* Seconds between callback tries */
157 #define CALLTIMEOUT CALLINTER_TRY*6 /* Total timeout for callback */
158 struct timeval udp_timeout
= { UDPTIMEOUT
, 0};
159 struct timeval tcp_timeout
= { 180, 0}; /* Timeout for map enumeration */
161 char *interdomain_value
; /* place to store the interdomain value */
164 int entry_count
; /* counts entries in the map */
165 char logfile
[] = "/var/yp/ypxfr.log";
166 static char err_usage
[] =
168 ypxfr [-f] [ -h host ] [ -d domainname ]\n\
169 [ -s domainname ] [-c] [-C tid prot servname ] map\n\n\
171 -f forces transfer even if the master's copy is not newer.\n\
172 host is the server from where the map should be transfered\n\
173 -d domainname is specified if other than the default domain\n\
174 -s domainname is a source for the map that is same across domains\n\
175 -c inhibits sending a \"Clear map\" message to the local ypserv.\n\
176 -C is for use only by ypserv to pass callback information.\n";
177 char err_bad_args
[] =
178 "%s argument is bad.\n";
179 char err_cant_get_kname
[] =
180 "Can't get %s back from system call.\n";
181 char err_null_kname
[] =
182 "%s hasn't been set on this machine.\n";
183 char err_bad_hostname
[] = "hostname";
184 char err_bad_mapname
[] = "mapname";
185 char err_bad_domainname
[] = "domainname";
186 char err_udp_failure
[] =
187 "Can't set up a udp connection to ypserv on host %s.\n";
188 char yptempname_prefix
[] = "ypxfr_map.";
189 char ypbkupname_prefix
[] = "ypxfr_bkup.";
191 void get_command_line_args();
192 bool bind_to_server();
194 bool get_private_recs();
198 bool get_misc_recs();
199 bool get_master_name();
200 bool get_v1master_name();
201 bool get_v2master_name();
202 void find_map_master();
204 unsigned get_local_version();
208 bool add_private_entries();
215 void send_callback();
216 int ypall_callback();
217 int map_yperr_to_pusherr();
218 extern CLIENT
*__yp_clnt_create_rsvdport();
220 bool_t
is_yptol_mode();
226 * This is the mainline for the ypxfr process.
236 static char default_domain_name
[YPMAXDOMAIN
];
237 static unsigned big
= 0xffffffff;
243 * Inter-process lock synchronization structure. Since slave servers
244 * get their maps from another NIS server rather than LDAP they can
245 * never run in N2L mode. We thus do not have to init the update
248 if (init_lock_map() == FALSE
) {
252 get_command_line_args(argc
, argv
);
256 if (!getdomainname(default_domain_name
, YPMAXDOMAIN
)) {
257 domain
= default_domain_name
;
259 logprintf(err_cant_get_kname
,
261 xfr_exit(YPPUSH_RSRC
);
264 if (strlen(domain
) == 0) {
265 logprintf(err_null_kname
,
267 xfr_exit(YPPUSH_RSRC
);
277 * if we were unable to get the master name, either from
278 * the -h option or from -C "name" option or from NIS,
282 xfr_exit(YPPUSH_MADDR
);
285 if (!bind_to_server(master
, &master_server
,
286 &master_prog_vers
, &status
)) {
290 if (!get_private_recs(&status
)) {
294 if (!master_version
) {
297 master_version
= &big
;
298 fake_master_version
= TRUE
;
301 "Can't get order number for map %s from server at %s: use the -f flag.\n",
303 xfr_exit(YPPUSH_FORCE
);
307 if (!move_map(&status
)) {
311 if (send_clear
&& !send_ypclear(&status
)) {
316 logprintf("Transferred map %s from %s (%d entries).\n",
317 map
, master
, entry_count
);
320 xfr_exit(YPPUSH_SUCC
);
326 * This decides whether we're being run interactively or not, and, if not,
327 * whether we're supposed to be logging or not. If we are logging, it sets
328 * up stderr to point to the log file, and sets the "logging"
329 * variable. If there's no logging, the output goes in the bit bucket.
330 * Logging output differs from interactive output in the presence of a
331 * timestamp, present only in the log file. stderr is reset, too, because it
332 * it's used by various library functions, including clnt_perror.
338 if (access(logfile
, W_OK
)) {
339 (void) freopen("/dev/null", "w", stderr
);
341 (void) freopen(logfile
, "a", stderr
);
347 * This constructs a logging record.
350 logprintf(arg1
, arg2
, arg3
, arg4
, arg5
, arg6
, arg7
)
357 (void) gettimeofday(&t
, NULL
);
358 (void) fprintf(stderr
, "%19.19s: ", ctime(&t
.tv_sec
));
360 (void) fprintf(stderr
, (char *)arg1
, arg2
, arg3
, arg4
, arg5
,
366 * This does the command line argument processing.
369 get_command_line_args(argc
, argv
)
377 logprintf(err_usage
);
378 xfr_exit(YPPUSH_BADARGS
);
383 if ((*argv
)[0] == '-') {
385 switch ((*argv
)[1]) {
428 if (strlen(master
) > 256) {
432 xfr_exit(YPPUSH_BADARGS
);
436 logprintf(err_usage
);
437 xfr_exit(YPPUSH_BADARGS
);
450 if (strlen(domain
) > YPMAXDOMAIN
) {
454 xfr_exit(YPPUSH_BADARGS
);
458 logprintf(err_usage
);
459 xfr_exit(YPPUSH_BADARGS
);
470 if (strlen(source
) > YPMAXDOMAIN
) {
474 xfr_exit(YPPUSH_BADARGS
);
478 logprintf(err_usage
);
479 xfr_exit(YPPUSH_BADARGS
);
488 pushhost
= *(++argv
);
489 if (strlen(pushhost
) > 256) {
490 logprintf(err_bad_args
, err_bad_hostname
);
492 xfr_exit(YPPUSH_BADARGS
);
497 logprintf(err_usage
);
498 xfr_exit(YPPUSH_BADARGS
);
503 interdomain_map
= TRUE
;
504 interdomain_value
= "";
512 logprintf(err_usage
);
513 xfr_exit(YPPUSH_BADARGS
);
524 if (strlen(map
) > YPMAXMAP
) {
525 logprintf(err_bad_args
,
527 xfr_exit(YPPUSH_BADARGS
);
531 logprintf(err_usage
);
532 xfr_exit(YPPUSH_BADARGS
);
538 logprintf(err_usage
);
539 xfr_exit(YPPUSH_BADARGS
);
544 * This tries to get the master name for the named map, from any
545 * server's version, using the vanilla NIS client interface. If we get a
546 * name back, the global "master" gets pointed to it.
553 if (err
= __yp_master_rsvdport(source
, map
, &master
)) {
554 logprintf("Can't get master of %s. Reason: %s.\n", map
,
574 strcpy(inmap
, "ypslaves.");
576 gethostname(inkey
, 256);
577 inkeylen
= strlen(inkey
);
579 err
= yp_match(source
, inmap
, inkey
, inkeylen
, &outval
, &outvallen
);
586 * This sets up a udp connection to speak the correct program and version
587 * to a NIS server. vers is set to YPVERS, doesn't give a damn about
591 bind_to_server(host
, pdomb
, vers
, status
)
593 struct dom_binding
*pdomb
;
597 if (ping_server(host
, pdomb
, YPVERS
, status
)) {
605 * This sets up a UDP channel to a server which is assumed to speak an input
606 * version of YPPROG. The channel is tested by pinging the server. In all
607 * error cases except "Program Version Number Mismatch", the error is
608 * reported, and in all error cases, the client handle is destroyed and the
609 * socket associated with the channel is closed.
612 ping_server(host
, pdomb
, vers
, status
)
614 struct dom_binding
*pdomb
;
618 enum clnt_stat rpc_stat
;
620 if ((pdomb
->dom_client
= __yp_clnt_create_rsvdport(host
, YPPROG
, vers
,
624 * if we are on a c2 system, we should only accept data
625 * from a server which is on a reserved port.
628 * NUKE this for 5.0DR.
631 * (pdomb->dom_server_addr.sin_family != AF_INET ||
632 * pdomb->dom_server_addr.sin_port >= IPPORT_RESERVED)) {
633 * clnt_destroy(pdomb->dom_client);
634 * close(pdomb->dom_socket);
635 * (void) logprintf("bind_to_server: \
636 * server is not using a privileged port\n");
637 * *status = YPPUSH_YPERR;
642 rpc_stat
= clnt_call(pdomb
->dom_client
, YPBINDPROC_NULL
,
643 xdr_void
, 0, xdr_void
, 0, udp_timeout
);
645 if (rpc_stat
== RPC_SUCCESS
) {
648 clnt_destroy(pdomb
->dom_client
);
649 if (rpc_stat
!= RPC_PROGVERSMISMATCH
) {
650 (void) clnt_perror(pdomb
->dom_client
,
651 "ypxfr: bind_to_server clnt_call error");
654 *status
= YPPUSH_RPC
;
658 logprintf("bind_to_server __clnt_create_rsvd error");
659 (void) clnt_pcreateerror("");
661 *status
= YPPUSH_RPC
;
667 * This gets values for the YP_LAST_MODIFIED and YP_MASTER_NAME keys from the
668 * master server's version of the map. Values are held in static variables
669 * here. In the success cases, global pointer variables are set to point at
673 get_private_recs(pushstat
)
676 static char anumber
[20];
677 static unsigned number
;
678 static char name
[YPMAXPEER
+ 1];
683 if (get_order(anumber
, &number
, &status
)) {
684 master_version
= &number
;
685 master_ascii_version
= anumber
;
686 if (debug
) fprintf(stderr
,
687 "ypxfr: Master Version is %s\n", master_ascii_version
);
692 if (debug
) fprintf(stderr
,
693 "ypxfr: Couldn't get map's master version number, \
694 status was %d\n", status
);
699 if (get_master_name(name
, &status
)) {
701 if (debug
) fprintf(stderr
,
702 "ypxfr: Maps master is '%s'\n", master_name
);
707 if (debug
) fprintf(stderr
,
708 "ypxfr: Couldn't get map's master name, status was %d\n",
712 master_name
= master
;
717 "ypxfr: Getting private records from master.\n");
718 if (get_misc_recs(&status
)) {
721 "ypxfr: Masters map %s secure and %s an interdomain map.\n",
722 (secure_map
) ? "is" : "is not",
723 (interdomain_map
) ? "is" : "is not");
729 "ypxfr: Couldn't get state of secure and interdomain flags in map.\n");
738 * This gets the map's order number from the master server
741 get_order(an
, n
, pushstat
)
746 if (master_prog_vers
== YPVERS
) {
747 return (get_v2order(an
, n
, pushstat
));
753 get_v2order(an
, n
, pushstat
)
758 struct ypreq_nokey req
;
759 struct ypresp_order resp
;
766 * Get the map''s order number, null-terminate it and store it,
767 * and convert it to binary and store it again.
771 if ((enum clnt_stat
) clnt_call(master_server
.dom_client
,
772 YPPROC_ORDER
, (xdrproc_t
)xdr_ypreq_nokey
, (char *)&req
,
773 (xdrproc_t
)xdr_ypresp_order
, (char *)&resp
,
774 udp_timeout
) == RPC_SUCCESS
) {
776 if (resp
.status
== YP_TRUE
) {
777 sprintf(an
, "%d", resp
.ordernum
);
780 } else if (resp
.status
!= YP_BADDB
) {
781 *pushstat
= ypprot_err(resp
.status
);
785 "(info) Can't get order number from ypserv at %s. Reason: %s.\n",
786 master
, yperr_string(
787 ypprot_err(resp
.status
)));
791 CLNT_FREERES(master_server
.dom_client
,
792 (xdrproc_t
)xdr_ypresp_order
,
795 *pushstat
= YPPUSH_RPC
;
796 logprintf("ypxfr(get_v2order) RPC call to %s failed", master
);
797 clnt_perror(master_server
.dom_client
, "");
804 * Pick up the state of the YP_SECURE and YP_INTERDOMAIN records from the
805 * master. Only works on 4.0 V2 masters that will match a YP_ private key
806 * when asked to explicitly.
809 get_misc_recs(pushstat
)
812 struct ypreq_key req
;
813 struct ypresp_val resp
;
818 req
.keydat
.dptr
= yp_secure
;
819 req
.keydat
.dsize
= yp_secure_sz
;
821 resp
.valdat
.dptr
= NULL
;
822 resp
.valdat
.dsize
= 0;
825 * Get the value of the IS_SECURE key in the map.
830 fprintf(stderr
, "ypxfr: Checking masters secure key.\n");
831 if ((enum clnt_stat
) clnt_call(master_server
.dom_client
,
832 YPPROC_MATCH
, (xdrproc_t
)xdr_ypreq_key
, (char *)&req
,
833 (xdrproc_t
)xdr_ypresp_val
, (char *)&resp
,
834 udp_timeout
) == RPC_SUCCESS
) {
835 if (resp
.status
== YP_TRUE
) {
837 fprintf(stderr
, "ypxfr: SECURE\n");
840 } else if ((resp
.status
!= YP_NOKEY
) &&
841 (resp
.status
!= YP_VERS
) &&
842 (resp
.status
!= YP_NOMORE
)) {
843 *pushstat
= ypprot_err(resp
.status
);
847 "(info) Can't get secure flag from ypserv at %s. Reason: %s.\n",
848 master
, yperr_string(
849 ypprot_err(resp
.status
)));
853 CLNT_FREERES(master_server
.dom_client
,
854 (xdrproc_t
)xdr_ypresp_val
,
857 *pushstat
= YPPUSH_RPC
;
858 logprintf("ypxfr(get_misc_recs) RPC call to %s failed", master
);
859 clnt_perror(master_server
.dom_client
, "");
863 fprintf(stderr
, "ypxfr: Checking masters INTERDOMAIN key.\n");
864 req
.keydat
.dptr
= yp_interdomain
;
865 req
.keydat
.dsize
= yp_interdomain_sz
;
867 resp
.valdat
.dptr
= NULL
;
868 resp
.valdat
.dsize
= 0;
871 * Get the value of the INTERDOMAIN key in the map.
874 if ((enum clnt_stat
) clnt_call(master_server
.dom_client
,
875 YPPROC_MATCH
, (xdrproc_t
)xdr_ypreq_key
, (char *)&req
,
876 (xdrproc_t
)xdr_ypresp_val
, (char *)&resp
,
877 udp_timeout
) == RPC_SUCCESS
) {
878 if (resp
.status
== YP_TRUE
) {
880 fprintf(stderr
, "ypxfr: INTERDOMAIN\n");
881 interdomain_map
= TRUE
;
882 interdomain_value
= (char *)malloc(resp
.valdat
.dsize
+1);
883 (void) memmove(interdomain_value
, resp
.valdat
.dptr
,
885 *(interdomain_value
+resp
.valdat
.dsize
) = '\0';
886 interdomain_sz
= resp
.valdat
.dsize
;
888 } else if ((resp
.status
!= YP_NOKEY
) &&
889 (resp
.status
!= YP_VERS
) &&
890 (resp
.status
!= YP_NOMORE
)) {
891 *pushstat
= ypprot_err(resp
.status
);
895 "(info) Can't get interdomain flag from ypserv at %s. Reason: %s.\n",
896 master
, yperr_string(
897 ypprot_err(resp
.status
)));
901 CLNT_FREERES(master_server
.dom_client
,
902 (xdrproc_t
)xdr_ypresp_val
,
905 *pushstat
= YPPUSH_RPC
;
906 logprintf("ypxfr(get_misc_recs) RPC call to %s failed", master
);
907 clnt_perror(master_server
.dom_client
, "");
915 * This gets the map's master name from the master server
918 get_master_name(name
, pushstat
)
922 if (master_prog_vers
== YPVERS
) {
923 return (get_v2master_name(name
, pushstat
));
929 get_v2master_name(name
, pushstat
)
933 struct ypreq_nokey req
;
934 struct ypresp_master resp
;
942 if ((enum clnt_stat
) clnt_call(master_server
.dom_client
,
943 YPPROC_MASTER
, (xdrproc_t
)xdr_ypreq_nokey
, (char *)&req
,
944 (xdrproc_t
)xdr_ypresp_master
, (char *)&resp
,
945 udp_timeout
) == RPC_SUCCESS
) {
947 if (resp
.status
== YP_TRUE
) {
948 strcpy(name
, resp
.master
);
950 } else if (resp
.status
!= YP_BADDB
) {
951 *pushstat
= ypprot_err(resp
.status
);
955 "(info) Can't get master name from ypserv at %s. Reason: %s.\n",
956 master
, yperr_string(
957 ypprot_err(resp
.status
)));
961 CLNT_FREERES(master_server
.dom_client
,
962 (xdrproc_t
)xdr_ypresp_master
,
965 *pushstat
= YPPUSH_RPC
;
967 "ypxfr(get_v2master_name) RPC call to %s failed", master
);
968 clnt_perror(master_server
.dom_client
, "");
975 * This does the work of transferring the map.
981 unsigned local_version
;
982 char map_name
[MAXNAMLEN
+ 1];
983 char tmp_name
[MAXNAMLEN
+ 1];
984 char bkup_name
[MAXNAMLEN
+ 1];
991 mkfilename(map_name
);
994 local_version
= get_local_version(map_name
);
995 if (debug
) fprintf(stderr
,
996 "ypxfr: Local version of map '%s' is %d\n",
997 map_name
, local_version
);
999 if (local_version
>= *master_version
) {
1001 "Map %s at %s is not more recent than local.\n",
1003 *pushstat
= YPPUSH_AGE
;
1008 mk_tmpname(yptempname_prefix
, tmp_name
);
1010 if (!new_mapfiles(tmp_name
)) {
1012 "Can't create temp map %s.\n", tmp_name
);
1013 *pushstat
= YPPUSH_FILE
;
1017 if ((hgstatus
= ypxfrd_getdbm(tmp_name
, master
, source
, map
)) < 0)
1020 "(info) %s %s %s ypxfrd getdbm failed (reason = %d) -- using ypxfr\n",
1021 master
, domain
, map
, hgstatus
);
1023 db
= dbm_open(tmp_name
, O_RDWR
+ O_CREAT
+ O_TRUNC
, 0644);
1026 "Can't dbm init temp map %s.\n", tmp_name
);
1027 del_mapfiles(tmp_name
);
1028 *pushstat
= YPPUSH_DBM
;
1031 if (defwrite
) dbm_setdefwrite(db
);
1033 if (!get_map(tmp_name
, pushstat
)) {
1034 del_mapfiles(tmp_name
);
1038 if (!add_private_entries(tmp_name
)) {
1039 del_mapfiles(tmp_name
);
1040 *pushstat
= YPPUSH_DBM
;
1045 * Decide whether the map just transferred is a secure map.
1046 * If we already know the local version was secure, we do not
1047 * need to check this version.
1050 key
.dptr
= yp_secure
;
1051 key
.dsize
= yp_secure_sz
;
1052 val
= dbm_fetch(db
, key
);
1053 if (val
.dptr
!= NULL
) {
1058 if (dbm_close_status(db
) < 0) {
1060 "Can't do dbm close operation on temp map %s.\n",
1062 del_mapfiles(tmp_name
);
1063 *pushstat
= YPPUSH_DBM
;
1067 if (!get_order(an
, &n
, pushstat
)) {
1070 if (n
!= *master_version
) {
1072 "Version skew at %s while transferring map %s.\n",
1074 del_mapfiles(tmp_name
);
1075 *pushstat
= YPPUSH_SKEW
;
1080 if (!count_mismatch(tmp_name
, entry_count
)) {
1081 del_mapfiles(tmp_name
);
1082 *pushstat
= YPPUSH_DBM
;
1086 /* touch up the map */
1087 db
= dbm_open(tmp_name
, 2, 0644);
1090 "Can't dbm init temp map %s.\n", tmp_name
);
1091 del_mapfiles(tmp_name
);
1092 *pushstat
= YPPUSH_DBM
;
1097 if (!add_private_entries(tmp_name
)) {
1098 del_mapfiles(tmp_name
);
1099 *pushstat
= YPPUSH_DBM
;
1104 * Decide whether the map just transferred is a secure map.
1105 * If we already know the local version was secure, we do not
1106 * need to check this version.
1109 key
.dptr
= yp_secure
;
1110 key
.dsize
= yp_secure_sz
;
1111 val
= dbm_fetch(db
, key
);
1112 if (val
.dptr
!= NULL
) {
1117 if (dbm_close_status(db
) < 0) {
1119 "Can't do dbm close operation on temp map %s.\n",
1121 del_mapfiles(tmp_name
);
1122 *pushstat
= YPPUSH_DBM
;
1128 if (lock_map(map_name
) == 0) {
1129 del_mapfiles(tmp_name
);
1130 logprintf("Lock error on %s\n", map_name
);
1131 *pushstat
= YPPUSH_FILE
;
1134 if (!check_map_existence(map_name
)) {
1136 if (!rename_map(tmp_name
, map_name
, secure_map
)) {
1137 del_mapfiles(tmp_name
);
1139 "Rename error: couldn't mv %s to %s.\n",
1140 tmp_name
, map_name
);
1141 *pushstat
= YPPUSH_FILE
;
1142 unlock_map(map_name
);
1147 mk_tmpname(ypbkupname_prefix
, bkup_name
);
1149 if (!rename_map(map_name
, bkup_name
, secure_map
)) {
1150 (void) rename_map(bkup_name
, map_name
, secure_map
);
1152 "Rename error: check that old %s is still intact.\n",
1154 del_mapfiles(tmp_name
);
1155 *pushstat
= YPPUSH_FILE
;
1156 unlock_map(map_name
);
1160 if (rename_map(tmp_name
, map_name
, secure_map
)) {
1161 del_mapfiles(bkup_name
);
1163 del_mapfiles(tmp_name
);
1164 (void) rename_map(bkup_name
, map_name
, secure_map
);
1166 "Rename error: check that old %s is still intact.\n",
1168 *pushstat
= YPPUSH_FILE
;
1169 unlock_map(map_name
);
1173 if (unlock_map(map_name
) == 0)
1180 * This tries to get the order number out of the local version of the map.
1181 * If the attempt fails for any version, the function will return "0"
1184 get_local_version(name
)
1192 if (!check_map_existence(name
)) {
1195 if (debug
) fprintf(stderr
,
1196 "ypxfr: Map does exist, checking version now.\n");
1198 if ((db
= dbm_open(name
, 0, 0)) == 0) {
1202 key
.dptr
= yp_last_modified
;
1203 key
.dsize
= yp_last_modified_sz
;
1204 val
= dbm_fetch(db
, key
);
1205 if (!val
.dptr
) { /* Check to see if dptr is NULL */
1208 if (val
.dsize
== 0 || val
.dsize
> 10) {
1211 /* Now save this value while we have it available */
1212 (void) memmove(number
, val
.dptr
, val
.dsize
);
1213 number
[val
.dsize
] = '\0';
1216 * Now check to see if it is 'secure'. If we haven't already
1217 * determined that it is secure in get_private_recs() then we check
1218 * the local map here.
1221 key
.dptr
= yp_secure
;
1222 key
.dsize
= yp_secure_sz
;
1223 val
= dbm_fetch(db
, key
);
1224 secure_map
= (val
.dptr
!= NULL
);
1228 * Now check to see if interdomain requests are made of the local
1229 * map. Keep the value around if they are.
1231 if (!interdomain_map
) {
1232 key
.dptr
= yp_interdomain
;
1233 key
.dsize
= yp_interdomain_sz
;
1234 val
= dbm_fetch(db
, key
);
1235 if (interdomain_map
= (val
.dptr
!= NULL
)) {
1236 interdomain_value
= (char *)malloc(val
.dsize
+1);
1237 (void) memmove(interdomain_value
, val
.dptr
, val
.dsize
);
1238 *(interdomain_value
+val
.dsize
) = '\0';
1239 interdomain_sz
= val
.dsize
;
1244 (void) dbm_close_status(db
);
1246 return ((unsigned)atoi(number
));
1250 * This constructs a file name for a map, minus its dbm_dir
1251 * or dbm_pag extensions
1260 /* Work out if we are in yptol mode */
1261 yptol_mode
= is_yptol_mode();
1263 len
= strlen(domain
) + strlen(map
) + strlen(ypdbpath
) + 3;
1265 len
+= strlen(NTOL_PREFIX
);
1267 if (len
> (MAXNAMLEN
+ 1)) {
1268 logprintf("Map name string too long.\n");
1271 (void) strcpy(ppath
, ypdbpath
);
1272 (void) strcat(ppath
, "/");
1273 (void) strcat(ppath
, domain
);
1274 (void) strcat(ppath
, "/");
1276 (void) strcat(ppath
, NTOL_PREFIX
);
1277 (void) strcat(ppath
, map
);
1281 * This returns a temporary name for a map transfer minus its dbm_dir or
1282 * dbm_pag extensions.
1285 mk_tmpname(prefix
, xfr_name
)
1289 char xfr_anumber
[10];
1296 xfr_number
= getpid();
1297 (void) sprintf(xfr_anumber
, "%d", xfr_number
);
1299 (void) strcpy(xfr_name
, ypdbpath
);
1300 (void) strcat(xfr_name
, "/");
1301 (void) strcat(xfr_name
, domain
);
1302 (void) strcat(xfr_name
, "/");
1303 (void) strcat(xfr_name
, prefix
);
1304 (void) strcat(xfr_name
, map
);
1305 (void) strcat(xfr_name
, ".");
1306 (void) strcat(xfr_name
, xfr_anumber
);
1310 * This deletes the .pag and .dir files which implement a map.
1312 * Note: No error checking is done here for a garbage input file name or for
1313 * failed unlink operations.
1316 del_mapfiles(basename
)
1319 char dbfilename
[MAXNAMLEN
+ 1];
1325 strcpy(dbfilename
, basename
);
1326 strcat(dbfilename
, dbm_pag
);
1328 strcpy(dbfilename
, basename
);
1329 strcat(dbfilename
, dbm_dir
);
1334 * This creates <pname>.dir and <pname>.pag
1340 char dbfile
[MAXNAMLEN
+ 1];
1344 if (!pname
|| ((len
= strlen(pname
)) == 0) ||
1345 (len
+ 5) > (MAXNAMLEN
+ 1)) {
1350 (void) strcpy(dbfile
, pname
);
1351 (void) strcat(dbfile
, dbm_dir
);
1353 if ((f
= open(dbfile
, (O_WRONLY
| O_CREAT
| O_TRUNC
), 0600)) >= 0) {
1355 (void) strcpy(dbfile
, pname
);
1356 (void) strcat(dbfile
, dbm_pag
);
1358 if ((f
= open(dbfile
, (O_WRONLY
| O_CREAT
| O_TRUNC
),
1372 count_callback(status
)
1375 if (status
!= YP_TRUE
) {
1377 if (status
!= YP_NOMORE
) {
1379 "Error from ypserv on %s (ypall_callback) = %s.\n",
1380 master
, yperr_string(ypprot_err(status
)));
1391 * This counts the entries in the dbm file after the transfer to
1392 * make sure that the dbm file was built correctly.
1393 * Returns TRUE if everything is OK, FALSE if they mismatch.
1396 count_mismatch(pname
, oldcount
)
1402 #ifdef REALLY_PARANOID
1403 struct ypall_callback cbinfo
;
1404 struct ypreq_nokey allreq
;
1406 struct dom_binding domb
;
1408 #endif /* REALLY_PARANOID */
1411 db
= dbm_open(pname
, 0, 0);
1413 for (key
= dbm_firstkey(db
);
1414 key
.dptr
!= NULL
; key
= dbm_nextkey(db
))
1416 dbm_close_status(db
);
1419 if (oldcount
!= entry_count
) {
1421 "*** Count mismatch in dbm file %s: old=%d, new=%d ***\n",
1422 map
, oldcount
, entry_count
);
1426 #ifdef REALLY_PARANOID
1428 if ((domb
.dom_client
= __yp_clnt_create_rsvdport(master
, YPPROG
,
1430 "tcp6", 0, 0)) == 0 &&
1431 (domb
.dom_client
= __yp_clnt_create_rsvdport(master
, YPPROG
,
1433 "tcp", 0, 0)) == 0) {
1434 clnt_pcreateerror("ypxfr (mismatch) - TCP channel "
1439 if (master_prog_vers
== YPVERS
) {
1442 allreq
.domain
= source
;
1444 cbinfo
.foreach
= count_callback
;
1446 cbinfo
.data
= (char *)&tmpstat
;
1449 s
= clnt_call(domb
.dom_client
, YPPROC_ALL
, xdr_ypreq_nokey
,
1450 &allreq
, xdr_ypall
, &cbinfo
, tcp_timeout
);
1453 if (s
== RPC_SUCCESS
) {
1455 clnt_perror(domb
.dom_client
,
1456 "ypxfr (get_map/all) - RPC clnt_call (TCP) failure");
1465 logprintf("Wrong version number!\n");
1468 clnt_destroy(domb
.dom_client
);
1469 close(domb
.dom_socket
);
1470 entry_count
+= 2; /* add in YP_entries */
1471 if (oldcount
!= entry_count
) {
1473 "*** Count mismatch after enumerate %s: old=%d, new=%d ***\n",
1474 map
, oldcount
, entry_count
);
1477 #endif /* REALLY_PARANOID */
1483 * This sets up a TCP connection to the master server, and either gets
1484 * ypall_callback to do all the work of writing it to the local dbm file
1485 * (if the ypserv is current version), or does it itself for an old ypserv.
1488 get_map(pname
, pushstat
)
1492 struct dom_binding domb
;
1494 struct ypreq_nokey allreq
;
1495 struct ypall_callback cbinfo
;
1496 bool retval
= FALSE
;
1498 int recvsiz
= 24 * 1024;
1499 struct netconfig
*nconf
;
1501 struct netbuf
*svcaddr
;
1502 char *netid
[] = { "tcp6", "tcp" };
1503 int i
, lastnetid
= (sizeof (netid
)/sizeof (netid
[0])) - 1;
1505 svcaddr
= (struct netbuf
*)calloc(1, sizeof (struct netbuf
));
1508 svcaddr
->maxlen
= 32;
1510 svcaddr
->buf
= (char *)malloc(32);
1511 if (! svcaddr
->buf
) {
1516 for (i
= 0; i
<= lastnetid
; i
++) {
1518 if ((nconf
= getnetconfigent(netid
[i
])) == NULL
) {
1521 logprintf("ypxfr: tcp transport not supported\n");
1526 if (rpcb_getaddr(YPPROG
, master_prog_vers
, nconf
, svcaddr
,
1528 freenetconfigent(nconf
);
1531 logprintf("ypxfr: could not get %s address\n", master
);
1536 if ((domb
.dom_client
= __nis_clnt_create(fd
, nconf
, 0, svcaddr
,
1537 0, YPPROG
, master_prog_vers
, recvsiz
, 0)) == 0) {
1538 freenetconfigent(nconf
);
1542 "ypxfr (get_map) - TCP channel create failure");
1543 *pushstat
= YPPUSH_RPC
;
1552 if (master_prog_vers
== YPVERS
) {
1553 allreq
.domain
= source
;
1555 cbinfo
.foreach
= ypall_callback
;
1557 cbinfo
.data
= (char *)&tmpstat
;
1559 s
= clnt_call(domb
.dom_client
, YPPROC_ALL
,
1560 (xdrproc_t
)xdr_ypreq_nokey
,
1561 (char *)&allreq
, (xdrproc_t
)xdr_ypall
, (char *)&cbinfo
,
1566 if (s
== RPC_SUCCESS
) {
1569 clnt_perror(domb
.dom_client
,
1570 "ypxfr (get_map/all) - RPC clnt_call (TCP) failure");
1571 *pushstat
= YPPUSH_RPC
;
1575 *pushstat
= tmpstat
;
1579 retval
= FALSE
; /* barf again at YPOLDVERS */
1581 clnt_destroy(domb
.dom_client
);
1586 * This sticks each key-value pair into the current map. It returns FALSE as
1587 * long as it wants to keep getting called back, and TRUE on error conditions
1588 * and "No more k-v pairs".
1591 ypall_callback(status
, key
, kl
, val
, vl
, pushstat
)
1603 if (status
!= YP_TRUE
) {
1605 if (status
!= YP_NOMORE
) {
1607 "Error from ypserv on %s (ypall_callback) = %s.\n",
1608 master
, yperr_string(ypprot_err(status
)));
1609 *pushstat
= map_yperr_to_pusherr(status
);
1620 /* way too many fetches */
1623 test
= dbm_fetch(db
, keydat
);
1624 if (test
.dptr
!= NULL
) {
1625 logprintf("Duplicate key %s in map %s\n", key
, map
);
1626 *pushstat
= YPPUSH_DBM
;
1629 #endif /* PARANOID */
1630 if (dbm_store(db
, keydat
, valdat
, 0) < 0) {
1632 "Can't do dbm store into temp map %s.\n", map
);
1633 *pushstat
= YPPUSH_DBM
;
1637 test
= dbm_fetch(db
, keydat
);
1638 if (test
.dptr
== NULL
) {
1639 logprintf("Key %s was not inserted into dbm file %s\n",
1641 *pushstat
= YPPUSH_DBM
;
1644 #endif /* PARANOID */
1646 if (dbm_error(db
)) {
1647 logprintf("Key %s dbm_error raised in file %s\n",
1649 *pushstat
= YPPUSH_DBM
;
1656 * This maps a YP_xxxx error code into a YPPUSH_xxxx error code
1659 map_yperr_to_pusherr(yperr
)
1667 reason
= YPPUSH_SUCC
;
1671 reason
= YPPUSH_NOMAP
;
1675 reason
= YPPUSH_NODOM
;
1679 reason
= YPPUSH_YPERR
;
1683 reason
= YPPUSH_BADARGS
;
1687 reason
= YPPUSH_YPERR
;
1691 reason
= YPPUSH_XFRERR
;
1699 * This writes the last-modified and master entries into the new dbm file
1702 add_private_entries(pname
)
1708 if (!fake_master_version
) {
1709 key
.dptr
= yp_last_modified
;
1710 key
.dsize
= yp_last_modified_sz
;
1711 val
.dptr
= master_ascii_version
;
1712 val
.dsize
= strlen(master_ascii_version
);
1714 if (dbm_store(db
, key
, val
, 1) < 0) {
1716 "Can't do dbm store into temp map %s.\n",
1724 key
.dptr
= yp_master_name
;
1725 key
.dsize
= yp_master_name_sz
;
1726 val
.dptr
= master_name
;
1727 val
.dsize
= strlen(master_name
);
1728 if (dbm_store(db
, key
, val
, 1) < 0) {
1730 "Can't do dbm store into temp map %s.\n",
1737 if (interdomain_map
) {
1738 key
.dptr
= yp_interdomain
;
1739 key
.dsize
= yp_interdomain_sz
;
1740 val
.dptr
= interdomain_value
;
1741 val
.dsize
= interdomain_sz
;
1742 if (dbm_store(db
, key
, val
, 1) < 0) {
1744 "Can't do dbm store into temp map %s.\n",
1752 key
.dptr
= yp_secure
;
1753 key
.dsize
= yp_secure_sz
;
1754 val
.dptr
= yp_secure
;
1755 val
.dsize
= yp_secure_sz
;
1756 if (dbm_store(db
, key
, val
, 1) < 0) {
1758 "Can't do dbm store into temp map %s.\n",
1770 * This sends a YPPROC_CLEAR message to the local ypserv process.
1773 send_ypclear(pushstat
)
1776 struct dom_binding domb
;
1777 char local_host_name
[256];
1778 unsigned int progvers
;
1781 if (gethostname(local_host_name
, 256)) {
1782 logprintf("Can't get local machine name.\n");
1783 *pushstat
= YPPUSH_RSRC
;
1787 if (!bind_to_server(local_host_name
, &domb
,
1788 &progvers
, &status
)) {
1789 *pushstat
= YPPUSH_CLEAR
;
1793 if ((enum clnt_stat
) clnt_call(domb
.dom_client
,
1794 YPPROC_CLEAR
, xdr_void
, 0, xdr_void
, 0,
1795 udp_timeout
) != RPC_SUCCESS
) {
1797 "Can't send ypclear message to ypserv on the local machine.\n");
1798 xfr_exit(YPPUSH_CLEAR
);
1805 * This decides if send_callback has to get called, and does the process exit.
1812 send_callback(&status
);
1815 if (status
== YPPUSH_SUCC
) {
1819 execlp("./yppush", "yppush", "-T", map
, 0);
1820 execlp("/usr/etc/yp/yppush", "yppush", "-T", map
, 0);
1831 * This sets up a UDP connection to the yppush process which contacted our
1832 * parent ypserv, and sends it a status on the requested transfer.
1835 send_callback(status
)
1838 struct yppushresp_xfr resp
;
1839 struct dom_binding domb
;
1841 resp
.transid
= (unsigned long) atoi(tid
);
1842 resp
.status
= (unsigned long) *status
;
1844 udp_timeout
.tv_sec
= CALLTIMEOUT
;
1846 if ((domb
.dom_client
= __yp_clnt_create_rsvdport(pushhost
,
1847 (ulong_t
)atoi(proto
),
1849 0, 0, 0)) == NULL
) {
1850 *status
= YPPUSH_RPC
;
1854 if ((enum clnt_stat
) clnt_call(domb
.dom_client
,
1855 YPPUSHPROC_XFRRESP
, (xdrproc_t
)xdr_yppushresp_xfr
,
1856 (char *)&resp
, xdr_void
, 0,
1857 udp_timeout
) != RPC_SUCCESS
) {
1858 *status
= YPPUSH_RPC
;
1864 * FUNCTION: is_yptol_mode();
1866 * DESCRIPTION: Determines if we should run in N2L or traditional mode based
1867 * on the presence of the N2L mapping file.
1869 * This is a copy of a function from libnisdb. If more than this
1870 * one function become required it may be worth linking the
1875 * OUTPUTS: TRUE = Run in N2L mode
1876 * FALSE = Run in traditional mode.
1881 struct stat filestat
;
1883 if (stat(NTOL_MAP_FILE
, &filestat
) != -1)