Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / usr.sbin / ypserv / ypxfr / ypxfr.c
blobc78dffedfb46ca6fdb958e5e7e15d7d366a9ad79
1 /* $NetBSD: ypxfr.c,v 1.18 2009/11/05 15:23:55 chuck Exp $ */
3 /*
4 * Copyright (c) 1994 Mats O Jansson <moj@stacken.kth.se>
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
17 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
29 #include <sys/cdefs.h>
30 #ifndef lint
31 __RCSID("$NetBSD: ypxfr.c,v 1.18 2009/11/05 15:23:55 chuck Exp $");
32 #endif
34 #include <sys/param.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <sys/socket.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
42 #include <err.h>
43 #include <netdb.h>
44 #include <string.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <syslog.h>
48 #include <unistd.h>
50 #include <rpc/rpc.h>
51 #include <rpc/xdr.h>
52 #include <rpcsvc/yp_prot.h>
53 #include <rpcsvc/ypclnt.h>
55 #include "yplib_host.h"
56 #include "ypdb.h"
57 #include "ypdef.h"
59 DBM *db;
61 static int yperr2yppush(int);
62 static int ypxfr_foreach(int, char *, int, char *, int, char *);
64 int main(int, char *[]);
65 int get_local_ordernum(char *, char *, u_int *);
66 int get_remote_ordernum(CLIENT *, char *, char *, u_int, u_int *);
67 void get_map(CLIENT *, char *, char *, struct ypall_callback *);
68 DBM *create_db(char *, char *, char *, size_t);
69 int install_db(char *, char *, char *);
70 int unlink_db(char *, char *, char *);
71 int add_order(DBM *, u_int);
72 int add_master(CLIENT *, char *, char *, DBM *);
73 int add_interdomain(CLIENT *, char *, char *, DBM *);
74 int add_secure(CLIENT *, char *, char *, DBM *);
75 int send_clear(CLIENT *);
76 int send_reply(CLIENT *, int, int);
78 int
79 main(int argc, char **argv)
81 int need_usage = 0, cflag = 0, fflag = 0, Cflag = 0;
82 int ch;
83 char *domain;
84 char *host = NULL;
85 char *srcdomain = NULL;
86 char *tid = NULL;
87 char *prog = NULL;
88 char *ipadd = NULL;
89 char *port = NULL;
90 char *map = NULL;
91 u_int ordernum, new_ordernum;
92 struct ypall_callback callback;
93 CLIENT *client;
94 char temp_map[MAXPATHLEN];
95 int status, xfr_status;
97 status = YPPUSH_SUCC;
98 client = NULL;
100 if (yp_get_default_domain(&domain))
101 errx(1, "can't get YP domain name");
103 while ((ch = getopt(argc, argv, "cd:fh:s:C:")) != -1) {
104 switch (ch) {
105 case 'c':
106 cflag = 1;
107 break;
109 case 'd':
110 domain = optarg;
111 break;
113 case 'f':
114 fflag = 1;
115 break;
117 case 'h':
118 host = optarg;
119 break;
121 case 's':
122 srcdomain = optarg;
123 break;
125 case 'C':
126 if (optind + 3 >= argc) {
127 need_usage = 1;
128 optind = argc;
129 break;
131 Cflag = 1;
132 tid = optarg;
133 prog = argv[optind++];
134 ipadd = argv[optind++];
135 port = argv[optind++];
136 break;
138 default:
139 need_usage = 1;
142 argc -= optind; argv += optind;
144 if (argc != 1)
145 need_usage = 1;
147 map = argv[0];
149 if (need_usage) {
150 status = YPPUSH_BADARGS;
151 fprintf(stderr, "usage: %s [-cf] [-d domain] [-h host] %s\n",
152 getprogname(),
153 "[-s domain] [-C tid prog ipadd port] mapname");
154 exit(1);
157 #ifdef DEBUG
158 openlog("ypxfr", LOG_PID, LOG_DAEMON);
160 syslog(LOG_DEBUG, "ypxfr: Arguments:");
161 syslog(LOG_DEBUG, "YP clear to local: %s", (cflag) ? "no" : "yes");
162 syslog(LOG_DEBUG, " Force transfer: %s", (fflag) ? "yes" : "no");
163 syslog(LOG_DEBUG, " domain: %s", domain);
164 syslog(LOG_DEBUG, " host: %s", host);
165 syslog(LOG_DEBUG, " source domain: %s", srcdomain);
166 syslog(LOG_DEBUG, " transid: %s", tid);
167 syslog(LOG_DEBUG, " prog: %s", prog);
168 syslog(LOG_DEBUG, " port: %s", port);
169 syslog(LOG_DEBUG, " ipadd: %s", ipadd);
170 syslog(LOG_DEBUG, " map: %s", map);
171 #endif
173 if (fflag != 0)
174 ordernum = 0;
175 else {
176 status = get_local_ordernum(domain, map, &ordernum);
177 if (status < 0)
178 goto punt;
181 #ifdef DEBUG
182 syslog(LOG_DEBUG, "Get Master");
183 #endif
185 if (host == NULL) {
186 if (srcdomain == NULL)
187 status = yp_master(domain, map, &host);
188 else
189 status = yp_master(srcdomain, map, &host);
191 if (status == 0)
192 status = YPPUSH_SUCC;
193 else {
194 status = YPPUSH_MADDR;
195 goto punt;
199 #ifdef DEBUG
200 syslog(LOG_DEBUG, "Connect host: %s", host);
201 #endif
203 client = yp_bind_host(host, YPPROG, YPVERS, 0, 1);
205 status = get_remote_ordernum(client, domain, map, ordernum,
206 &new_ordernum);
209 if (status == YPPUSH_SUCC) {
210 /* Create temporary db */
211 db = create_db(domain, map, temp_map, sizeof(temp_map));
212 if (db == NULL)
213 status = YPPUSH_DBM;
215 /* Add ORDER */
216 if (status > 0)
217 status = add_order(db, new_ordernum);
219 /* Add MASTER */
220 if (status > 0)
221 status = add_master(client, domain, map, db);
223 /* Add INTERDOMAIN */
224 if (status > 0)
225 status = add_interdomain(client, domain, map, db);
227 /* Add SECURE */
228 if (status > 0)
229 status = add_secure(client, domain, map, db);
231 if (status > 0) {
232 callback.foreach = ypxfr_foreach;
233 get_map(client, domain, map, &callback);
236 /* Close db */
237 if (db != NULL)
238 ypdb_close(db);
240 /* Rename db */
241 if (status > 0)
242 status = install_db(domain, map, temp_map);
243 else
244 (void) unlink_db(domain, map, temp_map);
247 punt:
248 xfr_status = status;
250 if (client != NULL)
251 clnt_destroy(client);
253 /* YP_CLEAR */
254 if (!cflag) {
255 client = yp_bind_local(YPPROG, YPVERS);
256 status = send_clear(client);
257 clnt_destroy(client);
260 if (Cflag > 0) {
261 /* Send Response */
262 client = yp_bind_host(ipadd, atoi(prog), 1, atoi(port), 0);
263 status = send_reply(client, xfr_status, atoi(tid));
264 clnt_destroy(client);
267 exit (0);
271 * yperr2yppush: convert error codes from functions like yp_order_host,
272 * yp_master_host, and yp_match_host into YPPUSH rpc status values.
274 static int
275 yperr2yppush(int yperr) {
276 switch (yperr) {
277 case YPERR_DOMAIN:
278 return(YPPUSH_NODOM);
279 case YPERR_MAP:
280 return(YPPUSH_NOMAP);
281 case YPERR_KEY:
282 return(YPPUSH_YPERR);
283 case YPERR_BADDB:
284 return(YPPUSH_YPERR);
288 * generic error status for the rest (BADARGS, RPC, YPERR, RESRC,
289 * NOMORE, PMAP, YPBIND, YPSERV, NODOM, VERS, ACCESS, BUSY)
291 return(YPPUSH_XFRERR); /* generic error status */
294 static int
295 ypxfr_foreach(int status, char *keystr, int keylen, char *valstr,
296 int vallen, char *data)
298 datum key, val;
300 if (status == YP_NOMORE)
301 return (0);
303 keystr[keylen] = '\0';
304 valstr[vallen] = '\0';
306 key.dptr = keystr;
307 key.dsize = strlen(keystr);
309 val.dptr = valstr;
310 val.dsize = strlen(valstr);
312 /* XXX: suspect... ignoring return value here */
313 ypdb_store(db, key, val, YPDB_INSERT);
315 return (0);
319 get_local_ordernum(char *domain, char *map, u_int *lordernum)
321 char map_path[1024];
322 char order_key[] = YP_LAST_KEY;
323 char order[MAX_LAST_LEN+1];
324 struct stat finfo;
325 DBM *ldb;
326 datum k, v;
327 unsigned int status;
329 status = YPPUSH_SUCC;
331 snprintf(map_path, sizeof(map_path), "%s/%s", YP_DB_PATH, domain);
333 /* Make sure we serve the domain. */
334 if ((stat(map_path, &finfo)) != 0 ||
335 (S_ISDIR(finfo.st_mode) == 0)) {
336 warnx("domain `%s' not found locally", domain);
337 status = YPPUSH_NODOM;
338 goto out;
341 /* Make sure we serve the map. */
342 snprintf(map_path, sizeof(map_path), "%s/%s/%s%s",
343 YP_DB_PATH, domain, map, YPDB_SUFFIX);
344 if (stat(map_path, &finfo) != 0) {
345 status = YPPUSH_NOMAP;
346 goto out;
349 /* Open the map file. */
350 snprintf(map_path, sizeof(map_path), "%s/%s/%s",
351 YP_DB_PATH, domain, map);
352 ldb = ypdb_open(map_path);
353 if (ldb == NULL) {
354 status = YPPUSH_DBM;
355 goto out;
358 k.dptr = (char *)&order_key;
359 k.dsize = YP_LAST_LEN;
361 v = ypdb_fetch(ldb, k);
363 if (v.dptr == NULL)
364 *lordernum = 0;
365 else {
366 strncpy(order, v.dptr, v.dsize);
367 order[v.dsize] = '\0';
368 *lordernum = (u_int)atoi((char *)&order);
370 ypdb_close(ldb);
372 out:
373 if ((status == YPPUSH_NOMAP) || (status == YPPUSH_DBM)) {
374 *lordernum = 0;
375 status = YPPUSH_SUCC;
378 return (status);
382 get_remote_ordernum(CLIENT *client, char *domain, char *map,
383 u_int lordernum, u_int *rordernum)
385 int status;
387 status = yp_order_host(client, domain, map, (int *)rordernum);
389 if (status == 0) {
390 if (*rordernum <= lordernum)
391 status = YPPUSH_AGE;
392 else
393 status = YPPUSH_SUCC;
394 } else {
395 status = yperr2yppush(status);
398 return status;
401 void
402 get_map(CLIENT *client, char *domain, char *map,
403 struct ypall_callback *incallback)
406 (void)yp_all_host(client, domain, map, incallback);
409 DBM *
410 create_db(char *domain, char *map, char *db_temp, size_t db_temp_len)
412 static const char template[] = "ypdbXXXXXX";
413 DBM *ldb;
415 snprintf(db_temp, db_temp_len, "%s/%s/%s",
416 YP_DB_PATH, domain, template);
418 ldb = ypdb_mktemp(db_temp);
420 return ldb;
424 install_db(char *domain, char *map, char *db_temp)
426 char db_name[MAXPATHLEN];
428 snprintf(db_name, sizeof(db_name), "%s/%s/%s%s",
429 YP_DB_PATH, domain, map, YPDB_SUFFIX);
431 if (rename(db_temp, db_name)) {
432 warn("can't rename `%s' -> `%s'", db_temp, db_name);
433 return YPPUSH_YPERR;
436 return YPPUSH_SUCC;
440 unlink_db(char *domain, char *map, char *db_temp)
443 if (unlink(db_temp)) {
444 warn("can't unlink `%s'", db_temp);
445 return YPPUSH_YPERR;
448 return YPPUSH_SUCC;
452 add_order(DBM *ldb, u_int ordernum)
454 char datestr[11];
455 datum key, val;
456 char keystr[] = YP_LAST_KEY;
457 int status;
459 snprintf(datestr, sizeof(datestr), "%010d", ordernum);
461 key.dptr = keystr;
462 key.dsize = strlen(keystr);
464 val.dptr = datestr;
465 val.dsize = strlen(datestr);
467 status = ypdb_store(ldb, key, val, YPDB_INSERT);
468 if(status >= 0)
469 status = YPPUSH_SUCC;
470 else
471 status = YPPUSH_DBM;
473 return (status);
477 add_master(CLIENT *client, char *domain, char *map, DBM *ldb)
479 char keystr[] = YP_MASTER_KEY;
480 char *master;
481 int status;
482 datum key, val;
484 master = NULL;
486 /* Get MASTER */
487 status = yp_master_host(client, domain, map, &master);
489 if (master != NULL) {
490 key.dptr = keystr;
491 key.dsize = strlen(keystr);
493 val.dptr = master;
494 val.dsize = strlen(master);
496 status = ypdb_store(ldb, key, val, YPDB_INSERT);
497 if (status >= 0)
498 status = YPPUSH_SUCC;
499 else
500 status = YPPUSH_DBM;
501 } else {
502 status = yperr2yppush(status);
505 return status;
509 add_interdomain(CLIENT *client, char *domain, char *map, DBM *ldb)
511 char keystr[] = YP_INTERDOMAIN_KEY;
512 char *value;
513 int vallen;
514 int status;
515 datum k, v;
517 /* Get INTERDOMAIN */
518 k.dptr = keystr;
519 k.dsize = strlen(keystr);
521 status = yp_match_host(client, domain, map,
522 k.dptr, k.dsize, &value, &vallen);
524 if (status == YPERR_KEY) {
525 /* this is an optional key/val, so it may not be present */
526 status = YPPUSH_SUCC;
527 } else if (status == 0 && value) {
528 v.dptr = value;
529 v.dsize = vallen;
531 if (v.dptr != NULL) {
532 status = ypdb_store(ldb, k, v, YPDB_INSERT);
533 if (status >= 0)
534 status = YPPUSH_SUCC;
535 else
536 status = YPPUSH_DBM;
538 } else {
539 status = yperr2yppush(status);
542 return status;
546 add_secure(CLIENT *client, char *domain, char *map, DBM *ldb)
548 char keystr[] = YP_SECURE_KEY;
549 char *value;
550 int vallen;
551 int status;
552 datum k, v;
554 /* Get SECURE */
555 k.dptr = keystr;
556 k.dsize = strlen(keystr);
558 status = yp_match_host(client, domain, map,
559 k.dptr, k.dsize, &value, &vallen);
561 if (status == YPERR_KEY) {
562 /* this is an optional key/val, so it may not be present */
563 status = YPPUSH_SUCC;
564 } else if (status == 0 && value != 0) {
565 v.dptr = value;
566 v.dsize = vallen;
568 if (v.dptr != NULL) {
569 status = ypdb_store(ldb, k, v, YPDB_INSERT);
570 if (status >= 0)
571 status = YPPUSH_SUCC;
572 else
573 status = YPPUSH_DBM;
575 } else {
576 status = yperr2yppush(status);
579 return status;
583 send_clear(CLIENT *client)
585 struct timeval tv;
586 int r;
587 int status;
589 status = YPPUSH_SUCC;
591 tv.tv_sec = 10;
592 tv.tv_usec = 0;
594 /* Send CLEAR */
595 r = clnt_call(client, YPPROC_CLEAR, xdr_void, 0, xdr_void, 0, tv);
596 if (r != RPC_SUCCESS) {
597 clnt_perror(client, "yp_clear: clnt_call");
598 status = YPPUSH_RPC;
601 return status;
605 send_reply(CLIENT *client, int status, int tid)
607 struct timeval tv;
608 struct ypresp_xfr resp;
609 int r;
611 tv.tv_sec = 10;
612 tv.tv_usec = 0;
614 resp.transid = tid;
615 resp.xfrstat = status;
617 /* Send XFRRESP */
618 r = clnt_call(client, YPPUSHPROC_XFRRESP, xdr_ypresp_xfr, &resp,
619 xdr_void, 0, tv);
620 if (r != RPC_SUCCESS) {
621 clnt_perror(client, "yppushresp_xdr: clnt_call");
622 status = YPPUSH_RPC;
625 return status;