freebsd-dev/gnu/libexec/ypxfr/ypxfr.c
Bill Paul c183a93033 Obtained from: The NYS project
This is a ported/modified version of the ypxfr program from the yps-0.21
package from the NYS project. This program is normally invoked by ypserv
when it receives a yppush command from an NIS master. It can also be
run from the command line to grab copies of maps when initializing a
slave server.

This program has been hacked in the following ways:

- rpcgen'ed new yp_xdr.c, yp_svc.c and yp_clnt.c files. The old ones were
  rather grody.

- Changed certain function names (prefended a _ to them) to avoid conflicts
  with certain functions lurking within libc. One major problem here is
  that ypxfr needs to bind to a YP master in order to work correctly,
  but it can't use the _yp_bind function inside libc because that
  function only lets you bind to a domain, not a specific host. Lots
  of head scratching here.

- Converted from GDBM to DB at gunpoint.

- Removed lots of really nasty looking DEBUG code to try to reduce clutter.

- Incorporated some of the library code supplied with yps-0.21 on which
  ypxfr was dependent.

This program still needs to be cleaned up just as a matter of principle:
I get all icky just looking at it sometimes.
1995-01-31 09:28:47 +00:00

373 lines
9.0 KiB
C

/*
YPS-0.2, NIS-Server for Linux
Copyright (C) 1994 Tobias Reber
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Modified for use with FreeBSD 2.x by Bill Paul (wpaul@ctr.columbia.edu)
$Id$
*/
/*
* $Author: root $
* $Log: ypxfr.c,v $
* Revision 2.0 1994/01/06 16:58:08 root
* Version 2.0
*
* Revision 0.20 1994/01/02 21:59:08 root
* Strict prototypes
*
* Revision 0.19 1994/01/02 20:10:08 root
* Added GPL notice
*
* Revision 0.18 1994/01/02 18:00:38 root
* New arguments for -C flag.
*
* Revision 0.17 1993/12/30 22:21:49 root
* Switch to GDBM
*
* Revision 0.16 1993/12/27 23:43:26 root
* Use dbm directly instead of makedbm
*
* Revision 0.15 1993/12/27 21:21:00 root
* This host should be the default master
*
* Revision 0.14 1993/12/19 12:41:55 root
* *** empty log message ***
*
* Revision 0.13 1993/06/12 10:49:35 root
* Align with include-4.4
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <paths.h>
#include <rpc/rpc.h>
#include <sys/types.h>
#include <db.h>
#include <limits.h>
#include <sys/stat.h>
DB *db;
#define PERM_SECURE (S_IRUSR|S_IWUSR)
HASHINFO openinfo = {
4096, /* bsize */
32, /* ffactor */
256, /* nelem */
2048 * 1024, /* cachesize */
NULL, /* hash */
0 /* lorder */
};
#include <rpcsvc/yp.h>
struct dom_binding {
struct dom_binding *dom_pnext;
char dom_domain[YPMAXDOMAIN + 1];
struct sockaddr_in dom_server_addr;
u_short dom_server_port;
int dom_socket;
CLIENT *dom_client;
u_short dom_local_port;
long dom_vers;
};
#define DATUM /* Otherwise ypclnt.h redefines datum */
#include <rpcsvc/ypclnt.h>
/*
* These are hooks to the ypclnt library in ../lib
*/
extern int _yp_bind(struct sockaddr_in *, char *);
extern int _yp_clear( char *);
#include <netdb.h>
#include <fcntl.h>
#include <ctype.h>
#include <arpa/inet.h>
extern int optind;
extern char *optarg;
static char *SourceHost=NULL, *TargetDomain=NULL, *SourceDomain=NULL;
static struct in_addr IpAddress;
static int Force=0, NoClear=0, TaskId=0, ProgramNumber=0,
PortNumber=0, Secure=0;
static char *
ypxfr_err_string(enum ypxfrstat y) {
switch(y) {
case YPXFR_SUCC: return "Success";
case YPXFR_AGE: return "Master's version not newer";
case YPXFR_NOMAP: return "Can't find server for map";
case YPXFR_NODOM: return "Domain not supported";
case YPXFR_RSRC: return "Local resource alloc failure";
case YPXFR_RPC: return "RPC failure talking to server";
case YPXFR_MADDR: return "Can't get master address";
case YPXFR_YPERR: return "YP server/map db error";
case YPXFR_BADARGS: return "Request arguments bad";
case YPXFR_DBM: return "Local dbm operation failed";
case YPXFR_FILE: return "Local file I/O operation failed";
case YPXFR_SKEW: return "Map version skew during transfer";
case YPXFR_CLEAR: return "Can't send \"Clear\" req to local ypserv";
case YPXFR_FORCE: return "No local order number in map use -f flag.";
case YPXFR_XFRERR: return "ypxfr error";
case YPXFR_REFUSED: return "Transfer request refused by ypserv";
}
}
ypxfr_foreach(int status, char *key, int keylen, char *val, int vallen,
int *data)
{
DBT outKey, outData;
if (status==YP_NOMORE)
return 0;
if (status!=YP_TRUE) {
int s=ypprot_err(status);
fprintf(stderr, "%s\n", yperr_string(s));
return 1;
}
outKey.data=key; outKey.size=(size_t)keylen;
outData.data=val; outData.size=(size_t)vallen;
(db->put)(db,&outKey,&outData,0);
return 0;
}
static enum ypxfrstat
ypxfr(char *mapName) {
int localOrderNum=0;
int masterOrderNum=0;
char *masterName;
struct sockaddr_in localHost;
struct sockaddr_in masterHost;
struct ypall_callback callback;
char dbName[1024];
char dbName2[1024];
int y, masterSock;
CLIENT *masterClient;
memset(&localHost, '\0', sizeof localHost);
localHost.sin_family=AF_INET;
localHost.sin_addr.s_addr=htonl(INADDR_LOOPBACK);
if (!SourceHost) {
if ((y=yp_master(SourceDomain, mapName, &masterName)))
return YPXFR_MADDR;
SourceHost=masterName;
}
memset(&masterHost, '\0', sizeof masterHost);
masterHost.sin_family=AF_INET;
{
struct hostent *h=gethostbyname(SourceHost);
if (!h) {
return YPXFR_MADDR;
}
memcpy(&masterHost.sin_addr, h->h_addr,
sizeof masterHost.sin_addr);
}
if ((y=_yp_bind(&masterHost, SourceDomain))) return YPXFR_RPC;
masterSock=RPC_ANYSOCK;
masterClient=clnttcp_create(&masterHost, YPPROG, YPVERS, &masterSock, 0, 0);
if (masterClient==NULL) {
clnt_pcreateerror("");
return YPXFR_RPC;
}
{
static struct timeval tv = { 25, 0 };
struct ypreq_nokey req;
struct ypresp_order resp;
int y;
req.domain=SourceDomain;
req.map=mapName;
y=clnt_call(masterClient, YPPROC_ORDER, xdr_ypreq_nokey,
&req, xdr_ypresp_order, &resp, tv);
if (y!=RPC_SUCCESS) {
clnt_perror(masterClient, "masterOrderNum");
masterOrderNum=0x7fffffff;
} else {
masterOrderNum=resp.ordernum;
}
xdr_free(xdr_ypresp_order, (char *)&resp);
}
if (!Force) {
DBT inKey, inVal;
sprintf(dbName, "%s/%s/%s", _PATH_YP, TargetDomain, mapName);
if ((db = dbopen(dbName,O_RDWR|O_EXCL, PERM_SECURE,
DB_HASH, &openinfo)) == NULL) {
perror("dbopen");
fprintf(stderr, "%s: cannot open - ignored.\n", dbName);
localOrderNum=0;
} else {
inKey.data="YP_LAST_MODIFIED"; inKey.size=strlen(inKey.data);
(db->get)(db,&inKey,&inVal,0);
if (inVal.data) {
int i;
char *d=inVal.data;
for (i=0; i<inVal.size; i++, d++) {
if (!isdigit(*d)) {
(void)(db->close)(db);
return YPXFR_SKEW;
}
}
localOrderNum=atoi(inVal.data);
}
(void)(db->close)(db);
}
if (localOrderNum>=masterOrderNum) return YPXFR_AGE;
}
sprintf(dbName, "%s/%s/%s~", _PATH_YP, TargetDomain, mapName);
if ((db = dbopen(dbName,O_RDWR|O_EXCL|O_CREAT, PERM_SECURE, DB_HASH,
&openinfo)) == NULL) {
fprintf(stderr, "%s: Cannot open\n", dbName);
return YPXFR_DBM;
}
{
DBT outKey, outData;
char orderNum[12];
outKey.data="YP_MASTER_NAME"; outKey.size=strlen(outKey.data);
outData.data=SourceHost; outData.size=strlen(outData.data);
(db->put)(db,&outKey,&outData,0);
sprintf(orderNum, "%d", masterOrderNum);
outKey.data="YP_LAST_MODIFIED"; outKey.size=strlen(outKey.data);
outData.data=orderNum; outData.size=strlen(outData.data);
(db->put)(db,&outKey,&outData,0);
}
callback.foreach = ypxfr_foreach;
callback.data = NULL;
y=__yp_all(SourceDomain, mapName, &callback);
(void)(db->close)(db);
sprintf(dbName, "%s/%s/%s~", _PATH_YP, TargetDomain, mapName);
sprintf(dbName2, "%s/%s/%s", _PATH_YP, TargetDomain, mapName);
unlink(dbName2);
rename(dbName, dbName2);
if (!NoClear) {
memset(&localHost, '\0', sizeof localHost);
localHost.sin_family=AF_INET;
localHost.sin_addr.s_addr=htonl(INADDR_LOOPBACK);
if (_yp_bind(&localHost, TargetDomain) ||
_yp_clear(TargetDomain)) return YPXFR_CLEAR;
}
return y==0?YPXFR_SUCC:YPXFR_YPERR;
}
void
main (int argc, char **argv)
{
while(1) {
int c=getopt(argc, argv, "fcd:h:s:C:S");
if (c==EOF) break;
switch (c) {
case 'f':
Force++;
break;
case 'c':
NoClear++;
break;
case 'd':
TargetDomain=optarg;
break;
case 'h':
SourceHost=optarg;
break;
case 's':
SourceDomain=optarg;
break;
case 'C':
TaskId=atoi(optarg);
ProgramNumber=atoi(argv[optind++]);
IpAddress.s_addr=inet_addr(argv[optind++]);
PortNumber=atoi(argv[optind++]);
break;
case 'S':
Secure++;
break;
}
}
argc-=optind;
argv+=optind;
if (!TargetDomain) {
yp_get_default_domain(&TargetDomain);
}
if (!SourceDomain) {
SourceDomain=TargetDomain;
}
for (; *argv; argv++) {
enum ypxfrstat y;
if ((y=ypxfr(*argv))!=YPXFR_SUCC) {
fprintf(stderr, "%s\n", ypxfr_err_string(y));
}
if (TaskId) {
struct sockaddr_in addr;
struct timeval wait;
CLIENT *clnt;
int s;
ypresp_xfr resp;
static struct timeval tv={0,0};
memset(&addr, '\0', sizeof addr);
addr.sin_addr=IpAddress;
addr.sin_port=htons(PortNumber);
addr.sin_family=AF_INET;
wait.tv_sec=25; wait.tv_usec=0;
s=RPC_ANYSOCK;
clnt=clntudp_create(&addr, ProgramNumber, 1, wait, &s);
if (!clnt) {
clnt_pcreateerror("ypxfr_callback");
continue;
}
resp.transid=TaskId;
resp.xfrstat=y;
switch (clnt_call(clnt, 1, xdr_ypresp_xfr, &resp,
xdr_void, NULL, tv)) {
case RPC_SUCCESS:
case RPC_TIMEDOUT:
break;
default:
clnt_perror(clnt, "ypxfr_callback");
}
clnt_destroy(clnt);
}
}
exit(0);
}