* Copyright (c) 1992, 1995 Eric P. Allman.
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
* %sccs.include.redist.c%
static char sccsid
[] = "@(#)map.c 8.78 (Berkeley) %G%";
struct dom_binding
; /* forward reference needed on IRIX */
# include <rpcsvc/ypclnt.h>
** MAP.C -- implementations for various map classes.
** Each map class implements a series of functions:
** bool map_parse(MAP *map, char *args)
** Parse the arguments from the config file. Return TRUE
** if they were ok, FALSE otherwise. Fill in map with the
** char *map_lookup(MAP *map, char *key, char **args, int *pstat)
** Look up the key in the given map. If found, do any
** rewriting the map wants (including "args" if desired)
** and return the value. Set *pstat to the appropriate status
** on error and return NULL. Args will be NULL if called
** from the alias routines, although this should probably
** not be relied upon. It is suggested you call map_rewrite
** to return the results -- it takes care of null termination
** and uses a dynamically expanded buffer as needed.
** void map_store(MAP *map, char *key, char *value)
** Store the key:value pair in the map.
** bool map_open(MAP *map, int mode)
** Open the map for the indicated mode. Mode should
** be either O_RDONLY or O_RDWR. Return TRUE if it
** was opened successfully, FALSE otherwise. If the open
** failed an the MF_OPTIONAL flag is not set, it should
** also print an error. If the MF_ALIAS bit is set
** and this map class understands the @:@ convention, it
** should call aliaswait() before returning.
** void map_close(MAP *map)
** This file also includes the implementation for getcanonname.
** It is currently implemented in a pretty ad-hoc manner; it ought
** to be more properly integrated into the map structure.
extern bool aliaswait
__P((MAP
*, char *, int));
extern bool extract_canonname
__P((char *, char *, char[]));
** MAP_PARSEARGS -- parse config line arguments for database lookup
** This is a generic version of the map_parse method.
** map -- the map being initialized.
** ap -- a pointer to the args on the config line.
** TRUE -- if everything parsed OK.
** null terminates the filename; stores it in map
map
->map_mflags
|= MF_TRY0NULL
| MF_TRY1NULL
;
while (isascii(*p
) && isspace(*p
))
map
->map_mflags
|= MF_INCLNULL
;
map
->map_mflags
&= ~MF_TRY0NULL
;
map
->map_mflags
&= ~MF_TRY1NULL
;
map
->map_mflags
|= MF_OPTIONAL
;
map
->map_mflags
|= MF_NOFOLDCASE
;
map
->map_mflags
|= MF_MATCHONLY
;
map
->map_mflags
|= MF_APPEND
;
map
->map_mflags
|= MF_KEEPQUOTES
;
while (isascii(*++p
) && isspace(*p
))
while (isascii(*++p
) && isspace(*p
))
map
->map_coldelim
= '\n';
map
->map_coldelim
= '\t';
map
->map_coldelim
= '\\';
map
->map_mflags
|= MF_DOMAIN_WIDE
;
while (*p
!= '\0' && !(isascii(*p
) && isspace(*p
)))
if (map
->map_app
!= NULL
)
map
->map_app
= newstr(map
->map_app
);
if (map
->map_keycolnm
!= NULL
)
map
->map_keycolnm
= newstr(map
->map_keycolnm
);
if (map
->map_valcolnm
!= NULL
)
map
->map_valcolnm
= newstr(map
->map_valcolnm
);
while (*p
!= '\0' && !(isascii(*p
) && isspace(*p
)))
map
->map_file
= newstr(map
->map_file
);
while (*p
!= '\0' && isascii(*p
) && isspace(*p
))
map
->map_rebuild
= newstr(p
);
if (map
->map_file
== NULL
&&
!bitset(MCF_OPTFILE
, map
->map_class
->map_cflags
))
syserr("No file name for %s map %s",
map
->map_class
->map_cname
, map
->map_mname
);
** MAP_REWRITE -- rewrite a database key, interpolating %n indications.
** It also adds the map_app string. It can be used as a utility
** in the map_lookup method.
** map -- the map that causes this.
** s -- the string to rewrite, NOT necessarily null terminated.
** slen -- the length of s.
** av -- arguments to interpolate into buf.
** Pointer to rewritten result. This is static data that
** should be copied if it is to be saved!
int rwb_len
; /* size of buffer */
char *rwb_buf
; /* ptr to buffer */
struct rwbuf RwBufs
[2]; /* buffers for rewriting output */
map_rewrite(map
, s
, slen
, av
)
register struct rwbuf
*rwb
;
printf("map_rewrite(%.*s), av =", slen
, s
);
for (avp
= av
; *avp
!= NULL
; avp
++)
/* count expected size of output (can safely overestimate) */
for (i
= slen
; --i
>= 0 && (c
= *bp
++) != 0; )
if (!(isascii(c
) && isdigit(c
)))
for (avp
= av
; --c
>= '0' && *avp
!= NULL
; avp
++)
if (map
->map_app
!= NULL
)
len
+= strlen(map
->map_app
);
if (rwb
->rwb_len
< ++len
)
/* need to malloc additional space */
if (rwb
->rwb_buf
!= NULL
)
rwb
->rwb_buf
= xalloc(rwb
->rwb_len
);
while (--slen
>= 0 && (c
= *s
++) != '\0')
if (--slen
< 0 || (c
= *s
++) == '\0')
if (!(isascii(c
) && isdigit(c
)))
for (avp
= av
; --c
>= '0' && *avp
!= NULL
; avp
++)
/* transliterate argument into output string */
for (ap
= *avp
; (c
= *ap
++) != '\0'; )
if (map
->map_app
!= NULL
)
strcpy(bp
, map
->map_app
);
printf("map_rewrite => %s\n", rwb
->rwb_buf
);
** INITMAPS -- initialize for aliasing
** rebuild -- if TRUE, this rebuilds the cached versions.
** e -- current envelope.
** if NDBM: opens the database.
** if ~NDBM: reads the aliases into the symbol table.
checkfd012("entering initmaps");
checkfd012("exiting initmaps");
if (!bitset(MF_VALID
, map
->map_mflags
))
printf("map_init(%s:%s, %s, %d)\n",
map
->map_class
->map_cname
== NULL
? "NULL" :
map
->map_class
->map_cname
,
map
->map_mname
== NULL
? "NULL" : map
->map_mname
,
map
->map_file
== NULL
? "NULL" : map
->map_file
,
if (rebuild
== (bitset(MF_ALIAS
, map
->map_mflags
) &&
bitset(MCF_REBUILDABLE
, map
->map_class
->map_cflags
) ? 1 : 2))
printf("\twrong pass\n");
/* if already open, close it (for nested open) */
if (bitset(MF_OPEN
, map
->map_mflags
))
map
->map_class
->map_close(map
);
map
->map_mflags
&= ~(MF_OPEN
|MF_WRITABLE
);
rebuildaliases(map
, FALSE
);
if (map
->map_class
->map_open(map
, O_RDONLY
))
printf("\t%s:%s %s: valid\n",
map
->map_class
->map_cname
== NULL
? "NULL" :
map
->map_class
->map_cname
,
map
->map_mname
== NULL
? "NULL" :
map
->map_file
== NULL
? "NULL" :
map
->map_mflags
|= MF_OPEN
;
printf("\t%s:%s %s: invalid: %s\n",
map
->map_class
->map_cname
== NULL
? "NULL" :
map
->map_class
->map_cname
,
map
->map_mname
== NULL
? "NULL" :
map
->map_file
== NULL
? "NULL" :
if (!bitset(MF_OPTIONAL
, map
->map_mflags
))
extern MAPCLASS BogusMapClass
;
map
->map_class
= &BogusMapClass
;
map
->map_mflags
|= MF_OPEN
;
** GETCANONNAME -- look up name using service switch
** host -- the host name to look up.
** hbsize -- the size of the host buffer.
** trymx -- if set, try MX records.
** TRUE -- if the host was found.
getcanonname(host
, hbsize
, trymx
)
char *maptype
[MAXMAPSTACK
];
short mapreturn
[MAXMAPACTIONS
];
nmaps
= switch_map_find("hosts", maptype
, mapreturn
);
for (mapno
= 0; mapno
< nmaps
; mapno
++)
printf("getcanonname(%s), trying %s\n",
if (strcmp("files", maptype
[mapno
]) == 0)
extern bool text_getcanonname
__P((char *, int, int *));
found
= text_getcanonname(host
, hbsize
, &stat
);
else if (strcmp("nis", maptype
[mapno
]) == 0)
extern bool nis_getcanonname
__P((char *, int, int *));
found
= nis_getcanonname(host
, hbsize
, &stat
);
else if (strcmp("nisplus", maptype
[mapno
]) == 0)
extern bool nisplus_getcanonname
__P((char *, int, int *));
found
= nisplus_getcanonname(host
, hbsize
, &stat
);
else if (strcmp("dns", maptype
[mapno
]) == 0)
extern bool dns_getcanonname
__P((char *, int, bool, int *));
found
= dns_getcanonname(host
, hbsize
, trymx
, &stat
);
/* see if we should continue */
else if (stat
== EX_NOHOST
)
if (bitset(1 << mapno
, mapreturn
[i
]))
printf("getcanonname(%s), found\n", host
);
** If returned name is still single token, compensate
** by tagging on $m. This is because some sites set
** up their DNS or NIS databases wrong.
if ((d
= strchr(host
, '.')) == NULL
|| d
[1] == '\0')
d
= macvalue('m', CurEnv
);
hbsize
> (int) (strlen(host
) + strlen(d
) + 1))
if (host
[strlen(host
) - 1] != '.')
printf("getcanonname(%s), failed, stat=%d\n", host
, stat
);
h_errno
= HOST_NOT_FOUND
;
** EXTRACT_CANONNAME -- extract canonical name from /etc/hosts entry
** name -- the name against which to match.
** line -- the /etc/hosts line.
** cbuf -- the location to store the result.
** TRUE -- if the line matched the desired name.
extract_canonname(name
, line
, cbuf
)
extern char *get_column();
p
= get_column(line
, i
, '\0', nbuf
);
(strchr(cbuf
, '.') == NULL
&& strchr(p
, '.') != NULL
))
if (strcasecmp(name
, p
) == 0)
if (found
&& strchr(cbuf
, '.') == NULL
)
/* try to add a domain on the end of the name */
char *domain
= macvalue('m', CurEnv
);
strlen(domain
) + strlen(cbuf
) + 1 < MAXNAME
)
** DBM_MAP_OPEN -- DBM-style map open
printf("ndbm_map_open(%s, %s, %d)\n",
map
->map_mname
, map
->map_file
, mode
);
dbm
= dbm_open(map
->map_file
, mode
, DBMMODE
);
if (aliaswait(map
, ".pag", FALSE
))
if (!bitset(MF_OPTIONAL
, map
->map_mflags
))
syserr("Cannot open DBM database %s", map
->map_file
);
map
->map_db1
= (void *) dbm
;
if (bitset(MF_ALIAS
, map
->map_mflags
) &&
!aliaswait(map
, ".pag", TRUE
))
/* exclusive lock for duration of rebuild */
fd
= dbm_dirfno((DBM
*) map
->map_db1
);
if (fd
>= 0 && !bitset(MF_LOCKED
, map
->map_mflags
) &&
lockfile(fd
, map
->map_file
, ".dir", LOCK_EX
))
map
->map_mflags
|= MF_LOCKED
;
if (fstat(dbm_dirfno((DBM
*) map
->map_db1
), &st
) >= 0)
map
->map_mtime
= st
.st_mtime
;
** DBM_MAP_LOOKUP -- look up a datum in a DBM-type map
ndbm_map_lookup(map
, name
, av
, statp
)
char keybuf
[MAXNAME
+ 1];
printf("ndbm_map_lookup(%s, %s)\n",
key
.dsize
= strlen(name
);
if (!bitset(MF_NOFOLDCASE
, map
->map_mflags
))
if (key
.dsize
> sizeof keybuf
- 1)
key
.dsize
= sizeof keybuf
- 1;
bcopy(key
.dptr
, keybuf
, key
.dsize
+ 1);
fd
= dbm_dirfno((DBM
*) map
->map_db1
);
if (fd
>= 0 && !bitset(MF_LOCKED
, map
->map_mflags
))
(void) lockfile(fd
, map
->map_file
, ".dir", LOCK_SH
);
if (bitset(MF_TRY0NULL
, map
->map_mflags
))
val
= dbm_fetch((DBM
*) map
->map_db1
, key
);
map
->map_mflags
&= ~MF_TRY1NULL
;
if (val
.dptr
== NULL
&& bitset(MF_TRY1NULL
, map
->map_mflags
))
val
= dbm_fetch((DBM
*) map
->map_db1
, key
);
map
->map_mflags
&= ~MF_TRY0NULL
;
if (fd
>= 0 && !bitset(MF_LOCKED
, map
->map_mflags
))
(void) lockfile(fd
, map
->map_file
, ".dir", LOCK_UN
);
if (bitset(MF_MATCHONLY
, map
->map_mflags
))
return map_rewrite(map
, name
, strlen(name
), NULL
);
return map_rewrite(map
, val
.dptr
, val
.dsize
, av
);
** DBM_MAP_STORE -- store a datum in the database
ndbm_map_store(map
, lhs
, rhs
)
printf("ndbm_map_store(%s, %s, %s)\n",
map
->map_mname
, lhs
, rhs
);
data
.dsize
= strlen(rhs
);
if (bitset(MF_INCLNULL
, map
->map_mflags
))
stat
= dbm_store((DBM
*) map
->map_db1
, key
, data
, DBM_INSERT
);
if (!bitset(MF_APPEND
, map
->map_mflags
))
usrerr("050 Warning: duplicate alias name %s", lhs
);
old
.dptr
= ndbm_map_lookup(map
, key
.dptr
, NULL
, &xstat
);
if (old
.dptr
!= NULL
&& *old
.dptr
!= '\0')
old
.dsize
= strlen(old
.dptr
);
if (data
.dsize
+ old
.dsize
+ 2 > bufsiz
)
bufsiz
= data
.dsize
+ old
.dsize
+ 2;
sprintf(buf
, "%s,%s", data
.dptr
, old
.dptr
);
data
.dsize
= data
.dsize
+ old
.dsize
+ 1;
printf("ndbm_map_store append=%s\n", data
.dptr
);
stat
= dbm_store((DBM
*) map
->map_db1
, key
, data
, DBM_REPLACE
);
syserr("readaliases: dbm put (%s)", lhs
);
** NDBM_MAP_CLOSE -- close the database
printf("ndbm_map_close(%s, %s, %x)\n",
map
->map_mname
, map
->map_file
, map
->map_mflags
);
if (bitset(MF_WRITABLE
, map
->map_mflags
))
inclnull
= bitset(MF_INCLNULL
, map
->map_mflags
);
map
->map_mflags
&= ~MF_INCLNULL
;
if (strstr(map
->map_file
, "/yp/") != NULL
)
(void) sprintf(buf
, "%010ld", curtime());
ndbm_map_store(map
, "YP_LAST_MODIFIED", buf
);
(void) gethostname(buf
, sizeof buf
);
ndbm_map_store(map
, "YP_MASTER_NAME", buf
);
map
->map_mflags
|= MF_INCLNULL
;
/* write out the distinguished alias */
ndbm_map_store(map
, "@", "@");
dbm_close((DBM
*) map
->map_db1
);
** NEWDB (Hash and BTree) Modules
** BT_MAP_OPEN, HASH_MAP_OPEN -- database open primitives.
** These do rather bizarre locking. If you can lock on open,
** do that to avoid the condition of opening a database that
** is being rebuilt. If you don't, we'll try to fake it, but
** there will be a race condition. If opening for read-only,
** we immediately release the lock to avoid freezing things up.
** We really ought to hold the lock, but guarantee that we won't
** be pokey about it. That's hard to do.
printf("bt_map_open(%s, %s, %d)\n",
map
->map_mname
, map
->map_file
, mode
);
omode
|= O_CREAT
|O_TRUNC
;
#if defined(O_EXLOCK) && HASFLOCK
(void) strcpy(buf
, map
->map_file
);
if (i
< 3 || strcmp(&buf
[i
- 3], ".db") != 0)
(void) strcat(buf
, ".db");
db
= dbopen(buf
, omode
, DBMMODE
, DB_BTREE
, NULL
);
if (aliaswait(map
, ".db", FALSE
))
if (!bitset(MF_OPTIONAL
, map
->map_mflags
))
syserr("Cannot open BTREE database %s", map
->map_file
);
# if defined(O_EXLOCK) && HASFLOCK
(void) lockfile(fd
, map
->map_file
, ".db", LOCK_UN
);
map
->map_mflags
|= MF_LOCKED
;
if (mode
== O_RDWR
&& fd
>= 0)
if (lockfile(fd
, map
->map_file
, ".db", LOCK_EX
))
map
->map_mflags
|= MF_LOCKED
;
/* try to make sure that at least the database header is on disk */
if (fd
>= 0 && fstat(fd
, &st
) >= 0)
map
->map_mtime
= st
.st_mtime
;
map
->map_db2
= (void *) db
;
if (mode
== O_RDONLY
&& bitset(MF_ALIAS
, map
->map_mflags
))
if (!aliaswait(map
, ".db", TRUE
))
** HASH_MAP_INIT -- HASH-style map initialization
printf("hash_map_open(%s, %s, %d)\n",
map
->map_mname
, map
->map_file
, mode
);
omode
|= O_CREAT
|O_TRUNC
;
#if defined(O_EXLOCK) && HASFLOCK
(void) strcpy(buf
, map
->map_file
);
if (i
< 3 || strcmp(&buf
[i
- 3], ".db") != 0)
(void) strcat(buf
, ".db");
db
= dbopen(buf
, omode
, DBMMODE
, DB_HASH
, NULL
);
if (aliaswait(map
, ".db", FALSE
))
if (!bitset(MF_OPTIONAL
, map
->map_mflags
))
syserr("Cannot open HASH database %s", map
->map_file
);
# if defined(O_EXLOCK) && HASFLOCK
(void) lockfile(fd
, map
->map_file
, ".db", LOCK_UN
);
map
->map_mflags
|= MF_LOCKED
;
if (mode
== O_RDWR
&& fd
>= 0)
if (lockfile(fd
, map
->map_file
, ".db", LOCK_EX
))
map
->map_mflags
|= MF_LOCKED
;
/* try to make sure that at least the database header is on disk */
if (fd
>= 0 && fstat(fd
, &st
) >= 0)
map
->map_mtime
= st
.st_mtime
;
map
->map_db2
= (void *) db
;
if (mode
== O_RDONLY
&& bitset(MF_ALIAS
, map
->map_mflags
))
if (!aliaswait(map
, ".db", TRUE
))
** DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map
db_map_lookup(map
, name
, av
, statp
)
register DB
*db
= (DB
*) map
->map_db2
;
char keybuf
[MAXNAME
+ 1];
printf("db_map_lookup(%s, %s)\n",
if (key
.size
> sizeof keybuf
- 1)
key
.size
= sizeof keybuf
- 1;
bcopy(name
, keybuf
, key
.size
+ 1);
if (!bitset(MF_NOFOLDCASE
, map
->map_mflags
))
if (fd
>= 0 && !bitset(MF_LOCKED
, map
->map_mflags
))
(void) lockfile(db
->fd(db
), map
->map_file
, ".db", LOCK_SH
);
if (bitset(MF_TRY0NULL
, map
->map_mflags
))
st
= db
->get(db
, &key
, &val
, 0);
map
->map_mflags
&= ~MF_TRY1NULL
;
if (st
!= 0 && bitset(MF_TRY1NULL
, map
->map_mflags
))
st
= db
->get(db
, &key
, &val
, 0);
map
->map_mflags
&= ~MF_TRY0NULL
;
if (fd
>= 0 && !bitset(MF_LOCKED
, map
->map_mflags
))
(void) lockfile(fd
, map
->map_file
, ".db", LOCK_UN
);
syserr("db_map_lookup: get (%s)", name
);
if (bitset(MF_MATCHONLY
, map
->map_mflags
))
return map_rewrite(map
, name
, strlen(name
), NULL
);
return map_rewrite(map
, val
.data
, val
.size
, av
);
** DB_MAP_STORE -- store a datum in the NEWDB database
db_map_store(map
, lhs
, rhs
)
register DB
*db
= map
->map_db2
;
printf("db_map_store(%s, %s, %s)\n",
map
->map_mname
, lhs
, rhs
);
if (bitset(MF_INCLNULL
, map
->map_mflags
))
stat
= db
->put(db
, &key
, &data
, R_NOOVERWRITE
);
if (!bitset(MF_APPEND
, map
->map_mflags
))
usrerr("050 Warning: duplicate alias name %s", lhs
);
old
.data
= db_map_lookup(map
, key
.data
, NULL
, &stat
);
old
.size
= strlen(old
.data
);
if (data
.size
+ old
.size
+ 2 > bufsiz
)
bufsiz
= data
.size
+ old
.size
+ 2;
sprintf(buf
, "%s,%s", data
.data
, old
.data
);
data
.size
= data
.size
+ old
.size
+ 1;
printf("db_map_store append=%s\n", data
.data
);
stat
= db
->put(db
, &key
, &data
, 0);
syserr("readaliases: db put (%s)", lhs
);
** DB_MAP_CLOSE -- add distinguished entries and close the database
register DB
*db
= map
->map_db2
;
printf("db_map_close(%s, %s, %x)\n",
map
->map_mname
, map
->map_file
, map
->map_mflags
);
if (bitset(MF_WRITABLE
, map
->map_mflags
))
/* write out the distinguished alias */
db_map_store(map
, "@", "@");
syserr("readaliases: db close failure");
** NIS_MAP_OPEN -- open DBM map
printf("nis_map_open(%s, %s)\n",
map
->map_mname
, map
->map_file
);
/* issue a pseudo-error message */
p
= strchr(map
->map_file
, '@');
if (*map
->map_file
== '\0')
map
->map_file
= "mail.aliases";
if (map
->map_domain
== NULL
)
yperr
= yp_get_default_domain(&map
->map_domain
);
if (!bitset(MF_OPTIONAL
, map
->map_mflags
))
syserr("421 NIS map %s specified, but NIS not running\n",
/* check to see if this map actually exists */
yperr
= yp_match(map
->map_domain
, map
->map_file
, "@", 1,
printf("nis_map_open: yp_match(%s, %s) => %s\n",
map
->map_domain
, map
->map_file
, yperr_string(yperr
));
if (yperr
== 0 || yperr
== YPERR_KEY
|| yperr
== YPERR_BUSY
)
if (!bitset(MF_ALIAS
, map
->map_mflags
) ||
aliaswait(map
, NULL
, TRUE
))
if (!bitset(MF_OPTIONAL
, map
->map_mflags
))
syserr("421 Cannot bind to map %s in domain %s: %s",
map
->map_file
, map
->map_domain
, yperr_string(yperr
));
** NIS_MAP_LOOKUP -- look up a datum in a NIS map
nis_map_lookup(map
, name
, av
, statp
)
char keybuf
[MAXNAME
+ 1];
printf("nis_map_lookup(%s, %s)\n",
if (buflen
> sizeof keybuf
- 1)
buflen
= sizeof keybuf
- 1;
bcopy(name
, keybuf
, buflen
+ 1);
if (!bitset(MF_NOFOLDCASE
, map
->map_mflags
))
if (bitset(MF_TRY0NULL
, map
->map_mflags
))
yperr
= yp_match(map
->map_domain
, map
->map_file
, keybuf
, buflen
,
map
->map_mflags
&= ~MF_TRY1NULL
;
if (yperr
== YPERR_KEY
&& bitset(MF_TRY1NULL
, map
->map_mflags
))
yperr
= yp_match(map
->map_domain
, map
->map_file
, keybuf
, buflen
,
map
->map_mflags
&= ~MF_TRY0NULL
;
if (yperr
!= YPERR_KEY
&& yperr
!= YPERR_BUSY
)
map
->map_mflags
&= ~(MF_VALID
|MF_OPEN
);
if (bitset(MF_MATCHONLY
, map
->map_mflags
))
return map_rewrite(map
, name
, strlen(name
), NULL
);
return map_rewrite(map
, vp
, vsize
, av
);
** NIS_GETCANONNAME -- look up canonical name in NIS
nis_getcanonname(name
, hbsize
, statp
)
static bool try0null
= TRUE
;
static bool try1null
= TRUE
;
static char *yp_domain
= NULL
;
char host_record
[MAXLINE
];
extern char *get_column();
printf("nis_getcanonname(%s)\n", name
);
if (strlen(name
) >= sizeof nbuf
)
(void) strcpy(nbuf
, name
);
/* we only accept single token search key */
yp_get_default_domain(&yp_domain
);
yperr
= yp_match(yp_domain
, "hosts.byname", nbuf
, keylen
,
if (yperr
== YPERR_KEY
&& try1null
)
yperr
= yp_match(yp_domain
, "hosts.byname", nbuf
, keylen
,
else if (yperr
== YPERR_BUSY
)
strncpy(host_record
, vp
, vsize
);
host_record
[vsize
] = '\0';
printf("got record `%s'\n", host_record
);
if (!extract_canonname(nbuf
, host_record
, cbuf
))
/* this should not happen, but.... */
if (hbsize
< strlen(cbuf
))
** This code donated by Sun Microsystems.
#undef NIS /* symbol conflict in nis.h */
#include <rpcsvc/nislib.h>
#define EN_col(col) zo_data.objdata_u.en_data.en_cols.en_cols_val[(col)].ec_value.ec_value_val
#define COL_NAME(res,i) ((res->objects.objects_val)->TA_data.ta_cols.ta_cols_val)[i].tc_name
#define COL_MAX(res) ((res->objects.objects_val)->TA_data.ta_cols.ta_cols_len)
#define PARTIAL_NAME(x) ((x)[strlen(x) - 1] != '.')
** NISPLUS_MAP_OPEN -- open nisplus table
nisplus_map_open(map
, mode
)
char qbuf
[MAXLINE
+ NIS_MAXNAMELEN
];
int retry_cnt
, max_col
, i
;
printf("nisplus_map_open(%s, %s, %d)\n",
map
->map_mname
, map
->map_file
, mode
);
if (*map
->map_file
== '\0')
map
->map_file
= "mail_aliases.org_dir";
if (PARTIAL_NAME(map
->map_file
) && map
->map_domain
== NULL
)
/* set default NISPLUS Domain to $m */
extern char *nisplus_default_domain();
map
->map_domain
= newstr(nisplus_default_domain());
printf("nisplus_map_open(%s): using domain %s\n",
map
->map_file
, map
->map_domain
);
if (!PARTIAL_NAME(map
->map_file
))
map
->map_domain
= newstr("");
/* check to see if this map actually exists */
if (PARTIAL_NAME(map
->map_file
))
sprintf(qbuf
, "%s.%s", map
->map_file
, map
->map_domain
);
strcpy(qbuf
, map
->map_file
);
while (res
== NULL
|| res
->status
!= NIS_SUCCESS
)
res
= nis_lookup(qbuf
, FOLLOW_LINKS
);
case NIS_NAMEUNREACHABLE
:
default: /* all other nisplus errors */
if (!bitset(MF_OPTIONAL
, map
->map_mflags
))
syserr("421 Cannot find table %s.%s: %s",
map
->map_file
, map
->map_domain
,
nis_sperrno(res
->status
));
sleep(2); /* try not to overwhelm hosed server */
if (NIS_RES_NUMOBJ(res
) != 1 ||
(NIS_RES_OBJECT(res
)->zo_data
.zo_type
!= TABLE_OBJ
))
printf("nisplus_map_open: %s is not a table\n", qbuf
);
if (!bitset(MF_OPTIONAL
, map
->map_mflags
))
syserr("421 %s.%s: %s is not a table",
map
->map_file
, map
->map_domain
,
nis_sperrno(res
->status
));
/* default key column is column 0 */
if (map
->map_keycolnm
== NULL
)
map
->map_keycolnm
= newstr(COL_NAME(res
,0));
/* verify the key column exist */
for (i
=0; i
< max_col
; i
++)
if (!strcmp(map
->map_keycolnm
, COL_NAME(res
,i
)))
printf("nisplus_map_open(%s): can not find key column %s\n",
map
->map_file
, map
->map_keycolnm
);
/* default value column is the last column */
if (map
->map_valcolnm
== NULL
)
map
->map_valcolno
= max_col
- 1;
for (i
=0; i
< max_col
; i
++)
if (strcmp(map
->map_valcolnm
, COL_NAME(res
,i
)) == 0)
printf("nisplus_map_open(%s): can not find column %s\n",
map
->map_file
, map
->map_keycolnm
);
** NISPLUS_MAP_LOOKUP -- look up a datum in a NISPLUS table
nisplus_map_lookup(map
, name
, av
, statp
)
char search_key
[MAXNAME
+ 1];
char qbuf
[MAXLINE
+ NIS_MAXNAMELEN
];
printf("nisplus_map_lookup(%s, %s)\n",
if (!bitset(MF_OPEN
, map
->map_mflags
))
if (nisplus_map_open(map
, O_RDONLY
))
map
->map_mflags
|= MF_OPEN
;
if (buflen
> sizeof search_key
- 1)
buflen
= sizeof search_key
- 1;
bcopy(name
, search_key
, buflen
+ 1);
if (!bitset(MF_NOFOLDCASE
, map
->map_mflags
))
/* construct the query */
if (PARTIAL_NAME(map
->map_file
))
sprintf(qbuf
, "[%s=%s],%s.%s", map
->map_keycolnm
,
search_key
, map
->map_file
, map
->map_domain
);
sprintf(qbuf
, "[%s=%s],%s", map
->map_keycolnm
,
search_key
, map
->map_file
);
printf("qbuf=%s\n", qbuf
);
result
= nis_list(qbuf
, FOLLOW_LINKS
| FOLLOW_PATH
, NULL
, NULL
);
if (result
->status
== NIS_SUCCESS
)
if ((count
= NIS_RES_NUMOBJ(result
)) != 1)
"%s:Lookup error, expected 1 entry, got (%d)",
/* ignore second entry */
printf("nisplus_map_lookup(%s), got %d entries, additional entries ignored\n",
vp
= ((NIS_RES_OBJECT(result
))->EN_col(map
->map_valcolno
));
/* set the length of the result */
printf("nisplus_map_lookup(%s), found %s\n",
if (bitset(MF_MATCHONLY
, map
->map_mflags
))
str
= map_rewrite(map
, name
, strlen(name
), NULL
);
str
= map_rewrite(map
, vp
, vsize
, av
);
if (result
->status
== NIS_NOTFOUND
)
else if (result
->status
== NIS_TRYAGAIN
)
map
->map_mflags
&= ~(MF_VALID
|MF_OPEN
);
if ((result
->status
!= NIS_NOTFOUND
) &&
(result
->status
!= NIS_TRYAGAIN
))
map
->map_mflags
&= ~(MF_VALID
|MF_OPEN
);
printf("nisplus_map_lookup(%s), failed\n", name
);
** NISPLUS_GETCANONNAME -- look up canonical name in NIS+
nisplus_getcanonname(name
, hbsize
, statp
)
char qbuf
[MAXLINE
+ NIS_MAXNAMELEN
];
if (strlen(name
) >= sizeof nbuf
)
(void) strcpy(nbuf
, name
);
sprintf(qbuf
, "[name=%s],hosts.org_dir", nbuf
);
/* multi token -- take only first token in nbuf */
sprintf(qbuf
, "[name=%s],hosts.org_dir.%s", nbuf
, &p
[1]);
printf("\nnisplus_getcanoname(%s), qbuf=%s\n",
result
= nis_list(qbuf
, EXPAND_NAME
|FOLLOW_LINKS
|FOLLOW_PATH
,
if (result
->status
== NIS_SUCCESS
)
if ((count
= NIS_RES_NUMOBJ(result
)) != 1)
"nisplus_getcanonname: Lookup error, expected 1 entry, got (%d)",
/* ignore second entry */
printf("nisplus_getcanoname(%s), got %d entries, addtional entries ignores\n", name
);
printf("nisplus_getcanoname(%s), found in directory \"%s\"\n",
name
, (NIS_RES_OBJECT(result
))->zo_domain
);
vp
= ((NIS_RES_OBJECT(result
))->EN_col(0));
printf("nisplus_getcanonname(%s), found %s\n",
if (strchr(vp
, '.') != NULL
)
domain
= macvalue('m', CurEnv
);
if (hbsize
> vsize
+ (int) strlen(domain
) + 1)
sprintf(name
, "%s.%s", vp
, domain
);
if (result
->status
== NIS_NOTFOUND
)
else if (result
->status
== NIS_TRYAGAIN
)
printf("nisplus_getcanonname(%s), failed, status=%d, nsw_stat=%d\n",
name
, result
->status
, *statp
);
static char default_domain
[MAXNAME
+ 1] = "";
if (default_domain
[0] != '\0')
p
= nis_local_directory();
strcpy(default_domain
, p
);
hes_map_lookup(map
, name
, av
, statp
)
printf("hes_map_lookup(%s, %s)\n", map
->map_file
, name
);
if (nl
< sizeof nbuf
- 1)
np
= xalloc(strlen(name
) + 2);
hp
= hes_resolve(np
, map
->map_file
);
hp
= hes_resolve(name
, map
->map_file
);
if (hp
== NULL
|| hp
[0] == NULL
)
if (bitset(MF_MATCHONLY
, map
->map_mflags
))
return map_rewrite(map
, name
, strlen(name
), NULL
);
return map_rewrite(map
, hp
[0], strlen(hp
[0]), av
);
#define NETINFO_DEFAULT_DIR "/aliases"
#define NETINFO_DEFAULT_PROPERTY "members"
** NI_MAP_OPEN -- open NetInfo Aliases
printf("ni_map_open: %s\n", map
->map_file
);
if (*map
->map_file
== '\0')
map
->map_file
= NETINFO_DEFAULT_DIR
;
if (map
->map_valcolnm
== NULL
)
map
->map_valcolnm
= NETINFO_DEFAULT_PROPERTY
;
if (map
->map_coldelim
== '\0' && bitset(MF_ALIAS
, map
->map_mflags
))
** NI_MAP_LOOKUP -- look up a datum in NetInfo
ni_map_lookup(map
, name
, av
, statp
)
extern char *ni_propval();
printf("ni_map_lookup(%s, %s)\n",
propval
= ni_propval(map
->map_file
, map
->map_keycolnm
, name
,
map
->map_valcolnm
, map
->map_coldelim
);
if (bitset(MF_MATCHONLY
, map
->map_mflags
))
res
= map_rewrite(map
, name
, strlen(name
), NULL
);
res
= map_rewrite(map
, propval
, strlen(propval
), av
);
** TEXT (unindexed text file) Modules
** This code donated by Sun Microsystems.
** TEXT_MAP_OPEN -- open text table
printf("text_map_open(%s, %s, %d)\n",
map
->map_mname
, map
->map_file
, mode
);
if (*map
->map_file
== '\0')
printf("text_map_open: file name required\n");
if (map
->map_file
[0] != '/')
printf("text_map_open(%s): file name must be fully qualified\n",
/* check to see if this map actually accessable */
if (access(map
->map_file
, R_OK
) <0)
/* check to see if this map actually exist */
if (stat(map
->map_file
, &sbuf
) <0)
printf("text_map_open(%s): can not stat %s\n",
map
->map_file
, map
->map_file
);
if (!S_ISREG(sbuf
.st_mode
))
printf("text_map_open(%s): %s is not a file\n",
map
->map_file
, map
->map_file
);
if (map
->map_keycolnm
== NULL
)
if (!isdigit(*map
->map_keycolnm
))
printf("text_map_open(%s): -k should specify a number, not %s\n",
map
->map_file
, map
->map_keycolnm
);
map
->map_keycolno
= atoi(map
->map_keycolnm
);
if (map
->map_valcolnm
== NULL
)
if (!isdigit(*map
->map_valcolnm
))
printf("text_map_open(%s): -v should specify a number, not %s\n",
map
->map_file
, map
->map_valcolnm
);
map
->map_valcolno
= atoi(map
->map_valcolnm
);
printf("text_map_open(%s): delimiter = ",
if (map
->map_coldelim
== '\0')
printf("(white space)\n");
printf("%c\n", map
->map_coldelim
);
** TEXT_MAP_LOOKUP -- look up a datum in a TEXT table
text_map_lookup(map
, name
, av
, statp
)
char search_key
[MAXNAME
+ 1];
extern char *get_column();
printf("text_map_lookup(%s)\n", name
);
if (buflen
> sizeof search_key
- 1)
buflen
= sizeof search_key
- 1;
bcopy(name
, search_key
, buflen
+ 1);
if (!bitset(MF_NOFOLDCASE
, map
->map_mflags
))
f
= fopen(map
->map_file
, "r");
map
->map_mflags
&= ~(MF_VALID
|MF_OPEN
);
key_idx
= map
->map_keycolno
;
delim
= map
->map_coldelim
;
while (fgets(linebuf
, MAXLINE
, f
))
continue; /* skip comment line */
if (lf
= strchr(linebuf
, '\n'))
if (!strcasecmp(search_key
,
get_column(linebuf
, key_idx
, delim
, buf
)))
vp
= get_column(linebuf
, map
->map_valcolno
, delim
, buf
);
if (bitset(MF_MATCHONLY
, map
->map_mflags
))
return map_rewrite(map
, name
, strlen(name
), NULL
);
return map_rewrite(map
, vp
, vsize
, av
);
** TEXT_GETCANONNAME -- look up canonical name in hosts file
text_getcanonname(name
, hbsize
, statp
)
extern char *get_column();
if (strlen(name
) >= sizeof nbuf
)
(void) strcpy(nbuf
, name
);
/* we only accept single token search key */
if (strchr(nbuf
, '.') != NULL
)
f
= fopen(HostsFile
, "r");
while (!found
&& fgets(linebuf
, MAXLINE
, f
) != NULL
)
if ((p
= strchr(linebuf
, '\n')) != NULL
)
found
= extract_canonname(nbuf
, linebuf
, cbuf
);
if (hbsize
>= strlen(cbuf
))
** STAB (Symbol Table) Modules
** STAB_MAP_LOOKUP -- look up alias in symbol table
stab_map_lookup(map
, name
, av
, pstat
)
printf("stab_lookup(%s, %s)\n",
s
= stab(name
, ST_ALIAS
, ST_FIND
);
** STAB_MAP_STORE -- store in symtab (actually using during init, not rebuild)
stab_map_store(map
, lhs
, rhs
)
s
= stab(lhs
, ST_ALIAS
, ST_ENTER
);
s
->s_alias
= newstr(rhs
);
** STAB_MAP_OPEN -- initialize (reads data file)
** This is a wierd case -- it is only intended as a fallback for
** aliases. For this reason, opens for write (only during a
** "newaliases") always fails, and opens for read open the
** actual underlying text file instead of the database.
printf("stab_map_open(%s, %s)\n",
map
->map_mname
, map
->map_file
);
af
= fopen(map
->map_file
, "r");
readaliases(map
, af
, FALSE
, FALSE
);
if (fstat(fileno(af
), &st
) >= 0)
map
->map_mtime
= st
.st_mtime
;
** Tries several types. For back compatibility of aliases.
** IMPL_MAP_LOOKUP -- lookup in best open database
impl_map_lookup(map
, name
, av
, pstat
)
printf("impl_map_lookup(%s, %s)\n",
if (bitset(MF_IMPL_HASH
, map
->map_mflags
))
return db_map_lookup(map
, name
, av
, pstat
);
if (bitset(MF_IMPL_NDBM
, map
->map_mflags
))
return ndbm_map_lookup(map
, name
, av
, pstat
);
return stab_map_lookup(map
, name
, av
, pstat
);
** IMPL_MAP_STORE -- store in open databases
impl_map_store(map
, lhs
, rhs
)
if (bitset(MF_IMPL_HASH
, map
->map_mflags
))
db_map_store(map
, lhs
, rhs
);
if (bitset(MF_IMPL_NDBM
, map
->map_mflags
))
ndbm_map_store(map
, lhs
, rhs
);
stab_map_store(map
, lhs
, rhs
);
** IMPL_MAP_OPEN -- implicit database open
printf("impl_map_open(%s, %s, %d)\n",
map
->map_mname
, map
->map_file
, mode
);
if (stat(map
->map_file
, &stb
) < 0)
/* no alias file at all */
map
->map_mflags
|= MF_IMPL_HASH
;
if (hash_map_open(map
, mode
))
#if defined(NDBM) && defined(NIS)
if (mode
== O_RDONLY
|| strstr(map
->map_file
, "/yp/") == NULL
)
map
->map_mflags
&= ~MF_IMPL_HASH
;
map
->map_mflags
|= MF_IMPL_NDBM
;
if (ndbm_map_open(map
, mode
))
map
->map_mflags
&= ~MF_IMPL_NDBM
;
#if defined(NEWDB) || defined(NDBM)
message("WARNING: cannot open alias database %s", map
->map_file
);
usrerr("Cannot rebuild aliases: no database format defined");
return stab_map_open(map
, mode
);
** IMPL_MAP_CLOSE -- close any open database(s)
printf("impl_map_close(%s, %s, %x)\n",
map
->map_mname
, map
->map_file
, map
->map_mflags
);
if (bitset(MF_IMPL_HASH
, map
->map_mflags
))
map
->map_mflags
&= ~MF_IMPL_HASH
;
if (bitset(MF_IMPL_NDBM
, map
->map_mflags
))
map
->map_mflags
&= ~MF_IMPL_NDBM
;
** Provides access to the system password file.
** USER_MAP_OPEN -- open user map
** Really just binds field names to field numbers.
printf("user_map_open(%s)\n", map
->map_mname
);
/* issue a pseudo-error message */
if (map
->map_valcolnm
== NULL
)
else if (strcasecmp(map
->map_valcolnm
, "name") == 0)
else if (strcasecmp(map
->map_valcolnm
, "passwd") == 0)
else if (strcasecmp(map
->map_valcolnm
, "uid") == 0)
else if (strcasecmp(map
->map_valcolnm
, "gid") == 0)
else if (strcasecmp(map
->map_valcolnm
, "gecos") == 0)
else if (strcasecmp(map
->map_valcolnm
, "dir") == 0)
else if (strcasecmp(map
->map_valcolnm
, "shell") == 0)
syserr("User map %s: unknown column name %s",
map
->map_mname
, map
->map_valcolnm
);
** USER_MAP_LOOKUP -- look up a user in the passwd file.
user_map_lookup(map
, key
, av
, statp
)
printf("user_map_lookup(%s, %s)\n",
if (bitset(MF_MATCHONLY
, map
->map_mflags
))
return map_rewrite(map
, key
, strlen(key
), NULL
);
switch (map
->map_valcolno
)
sprintf(buf
, "%d", pw
->pw_uid
);
sprintf(buf
, "%d", pw
->pw_gid
);
return map_rewrite(map
, rwval
, strlen(rwval
), av
);
** This provides access to arbitrary programs. It should be used
** only very sparingly, since there is no way to bound the cost
** of invoking an arbitrary program.
prog_map_lookup(map
, name
, av
, statp
)
printf("prog_map_lookup(%s, %s) %s\n",
map
->map_mname
, name
, map
->map_file
);
argv
[i
++] = map
->map_file
;
strcpy(buf
, map
->map_rebuild
);
for (p
= strtok(buf
, " \t"); p
!= NULL
; p
= strtok(NULL
, " \t"))
pid
= prog_open(argv
, &fd
, CurEnv
);
if (!bitset(MF_OPTIONAL
, map
->map_mflags
))
syserr("prog_map_lookup(%s) failed (%s) -- closing",
map
->map_mname
, errstring(errno
));
printf("prog_map_lookup(%s) failed (%s) -- closing",
map
->map_mname
, errstring(errno
));
map
->map_mflags
&= ~(MF_VALID
|MF_OPEN
);
i
= read(fd
, buf
, sizeof buf
- 1);
syserr("prog_map_lookup(%s): read error %s\n",
map
->map_mname
, errstring(errno
));
else if (i
== 0 && tTd(38, 2))
printf("prog_map_lookup(%s): empty answer\n",
/* collect the return value */
if (bitset(MF_MATCHONLY
, map
->map_mflags
))
rval
= map_rewrite(map
, name
, strlen(name
), NULL
);
rval
= map_rewrite(map
, buf
, strlen(buf
), NULL
);
/* now flush any additional output */
while ((i
= read(fd
, buf
, sizeof buf
)) > 0)
/* wait for the process to terminate */
syserr("prog_map_lookup(%s): wait error %s\n",
map
->map_mname
, errstring(errno
));
else if (WIFEXITED(stat
))
*statp
= WEXITSTATUS(stat
);
syserr("prog_map_lookup(%s): child died on signal %d",
** Tries each map in order until something matches, much like
** implicit. Stores go to the first map in the list that can
** This is slightly unusual in that there are two interfaces.
** The "sequence" interface lets you stack maps arbitrarily.
** The "switch" interface builds a sequence map by looking
** at a system-dependent configuration file such as
** /etc/nsswitch.conf on Solaris or /etc/svc.conf on Ultrix.
** We don't need an explicit open, since all maps are
** opened during startup, including underlying maps.
** SEQ_MAP_PARSE -- Sequenced map parsing
printf("seq_map_parse(%s, %s)\n", map
->map_mname
, ap
);
/* find beginning of map name */
while (isascii(*ap
) && isspace(*ap
))
for (p
= ap
; isascii(*p
) && isalnum(*p
); p
++)
while (*p
!= '\0' && (!isascii(*p
) || !isalnum(*p
)))
s
= stab(ap
, ST_MAP
, ST_FIND
);
syserr("Sequence map %s: unknown member map %s",
else if (maxmap
== MAXMAPSTACK
)
syserr("Sequence map %s: too many member maps (%d max)",
map
->map_mname
, MAXMAPSTACK
);
else if (maxmap
< MAXMAPSTACK
)
map
->map_stack
[maxmap
++] = &s
->s_map
;
** SWITCH_MAP_OPEN -- open a switched map
** This looks at the system-dependent configuration and builds
** a sequence map that does the same thing.
** Every system must define a switch_map_find routine in conf.c
** that will return the list of service types associated with a
switch_map_open(map
, mode
)
char *maptype
[MAXMAPSTACK
];
printf("switch_map_open(%s, %s, %d)\n",
map
->map_mname
, map
->map_file
, mode
);
nmaps
= switch_map_find(map
->map_file
, maptype
, map
->map_return
);
printf("\tswitch_map_find => %d\n", nmaps
);
for (mapno
= 0; mapno
< nmaps
; mapno
++)
printf("\t\t%s\n", maptype
[mapno
]);
if (nmaps
<= 0 || nmaps
> MAXMAPSTACK
)
for (mapno
= 0; mapno
< nmaps
; mapno
++)
if (maptype
[mapno
] == NULL
)
(void) sprintf(nbuf
, "%s.%s", map
->map_file
, maptype
[mapno
]);
s
= stab(nbuf
, ST_MAP
, ST_FIND
);
syserr("Switch map %s: unknown member map %s",
map
->map_stack
[mapno
] = &s
->s_map
;
printf("\tmap_stack[%d] = %s:%s\n",
mapno
, s
->s_map
.map_class
->map_cname
,
** SEQ_MAP_CLOSE -- close all underlying maps
printf("seq_map_close(%s)\n", map
->map_mname
);
for (mapno
= 0; mapno
< MAXMAPSTACK
; mapno
++)
MAP
*mm
= map
->map_stack
[mapno
];
if (mm
== NULL
|| !bitset(MF_OPEN
, mm
->map_mflags
))
mm
->map_class
->map_close(mm
);
mm
->map_mflags
&= ~(MF_OPEN
|MF_WRITABLE
);
** SEQ_MAP_LOOKUP -- sequenced map lookup
seq_map_lookup(map
, key
, args
, pstat
)
printf("seq_map_lookup(%s, %s)\n", map
->map_mname
, key
);
for (mapno
= 0; mapno
< MAXMAPSTACK
; mapbit
<<= 1, mapno
++)
MAP
*mm
= map
->map_stack
[mapno
];
if (!bitset(MF_OPEN
, mm
->map_mflags
))
if (bitset(mapbit
, map
->map_return
[MA_UNAVAIL
]))
rv
= mm
->map_class
->map_lookup(mm
, key
, args
, &stat
);
if (stat
== 0 && bitset(mapbit
, map
->map_return
[MA_NOTFOUND
]))
if (stat
!= 0 && bitset(mapbit
, map
->map_return
[MA_TRYAGAIN
]))
** SEQ_MAP_STORE -- sequenced map store
seq_map_store(map
, key
, val
)
printf("seq_map_store(%s, %s, %s)\n",
map
->map_mname
, key
, val
);
for (mapno
= 0; mapno
< MAXMAPSTACK
; mapno
++)
MAP
*mm
= map
->map_stack
[mapno
];
if (mm
== NULL
|| !bitset(MF_WRITABLE
, mm
->map_mflags
))
mm
->map_class
->map_store(mm
, key
, val
);
syserr("seq_map_store(%s, %s, %s): no writable map",
map
->map_mname
, key
, val
);
null_map_store(map
, key
, val
)
bogus_map_lookup(map
, key
, args
, pstat
)
NULL
, bogus_map_lookup
, null_map_store
,
null_map_open
, null_map_close
,