/*
* Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
* Reserved. This file contains Original Code and/or Modifications of
* Original Code as defined in and that are subject to the Apple Public
* Source License Version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. Please obtain a copy of the
* License at http://www.apple.com/publicsource and read it before using
* this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License."
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
* NIS.c
*
* NIS lookup agent for lookupd
* Written by Marc Majka
*/
#include <NetInfo/system_log.h>
#include <NetInfo/syslock.h>
#ifdef RPC_SUCCESS
#undef RPC_SUCCESS
#endif
#include <rpc/rpc.h>
#include <rpcsvc/yp_prot.h>
#include <rpcsvc/ypclnt.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <net/if.h>
#include <netinet/if_ether.h>
#include <stdio.h>
#include <stdlib.h>
#include <NetInfo/dsutil.h>
#include <NetInfo/DynaAPI.h>
#include <NetInfo/ffparser.h>
#include <NetInfo/config.h>
extern int _yplib_timeout;
extern int close(int);
extern char *nettoa(unsigned long);
static syslock *rpcLock = NULL;
#define BUFSIZE 8192
#define DefaultTimeToLive 300
#define SERVER_CHECK_LATENCY 60
typedef struct
{
char *nis_domain_name;
int map_order_number[20];
int map_order_time[20];
unsigned int timeToLive;
dynainfo *dyna;
} agent_private;
static char *categoryMap[] =
{
"passwd.byname",
"group.byname",
"hosts.byname",
"networks.byname",
"services.byname",
"protocols.byname",
"rpc.byname",
"mounts.byname",
"printcap.byname",
"bootparams.byname",
"bootptab.byaddr",
"mail.aliases",
NULL,
NULL,
"netgroup",
NULL,
NULL
};
static int categoryMapIndex[] =
{
0, /* passwd.byname */
2, /* group.byname */
4, /* hosts.byname */
6, /* networks.byname */
8, /* services.byname */
9, /* protocols.byname */
11, /* rpc.byname */
13, /* mounts.byname */
14, /* printcap.byname */
15, /* bootparams.byname */
16, /* bootptab.byaddr */
18, /* mail.aliases */
-1,
-1,
19, /* netgroup */
-1,
-1
};
static char *singleMap[] =
{
"passwd.byname", /* 0 */
"passwd.byuid", /* 1 */
"group.byname", /* 2 */
"group.bygid", /* 3 */
"hosts.byname", /* 4 */
"hosts.byaddr", /* 5 */
"networks.byname", /* 6 */
"networks.byaddr", /* 7 */
"services.byname", /* 8 */
"protocols.byname", /* 9 */
"protocols.bynumber", /* 10 */
"rpc.byname", /* 11 */
"rpc.bynumber", /* 12 */
"mounts.byname", /* 13 */
"printcap.byname", /* 14 */
"bootparams.byname", /* 15 */
"bootptab.byaddr", /* 16 */
"bootptab.byether", /* 17 */
"mail.aliases", /* 18 */
"netgroup" /* 19 */
};
u_int32_t
NIS_new(void **c, char *args, dynainfo *d)
{
agent_private *ap;
dsrecord *r;
dsattribute *a;
dsdata *x;
int i, status;
char *dn;
if (c == NULL) return 1;
rpcLock = syslock_get(RPCLockName);
syslock_lock(rpcLock);
if (args == NULL) yp_get_default_domain(&dn);
else dn = args;
syslock_unlock(rpcLock);
if (dn == NULL) return 1;
syslock_lock(rpcLock);
status = yp_bind(dn);
syslock_unlock(rpcLock);
if (status != 0) return 1;
ap = (agent_private *)malloc(sizeof(agent_private));
*c = ap;
ap->nis_domain_name = copyString(dn);
for (i = 0; i < 20; i++)
{
ap->map_order_number[i] = 0;
ap->map_order_time[i] = 0;
}
ap->dyna = d;
system_log(LOG_DEBUG, "Allocated NIS 0x%08x\n", (int)ap);
ap->timeToLive = DefaultTimeToLive;
r = NULL;
if (ap->dyna != NULL)
{
if (ap->dyna->dyna_config_agent != NULL)
{
status = (ap->dyna->dyna_config_agent)(ap->dyna, -1, &r);
if (status == 0)
{
x = cstring_to_dsdata("TimeToLive");
a = dsrecord_attribute(r, x, SELECT_ATTRIBUTE);
dsdata_release(x);
if (a != NULL)
{
x = dsattribute_value(a, 0);
if (x != NULL)
{
ap->timeToLive = atoi(dsdata_to_cstring(x));
dsdata_release(x);
}
dsattribute_release(a);
}
dsrecord_release(r);
}
}
}
return 0;
}
u_int32_t
NIS_free(void *c)
{
agent_private *ap;
if (c == NULL) return 0;
ap = (agent_private *)c;
if (ap->nis_domain_name != NULL) free(ap->nis_domain_name);
ap->nis_domain_name = NULL;
system_log(LOG_DEBUG, "Deallocated NIS 0x%08x\n", (int)ap);
free(ap);
c = NULL;
return 0;
}
static int
get_order_number(agent_private *ap, int map_index)
{
time_t now;
int order, status;
if (map_index < 0) return 0;
if (map_index >= 20) return 0;
now = time(0);
if (now <= ap->map_order_time[map_index]) return ap->map_order_number[map_index];
order = 0;
syslock_lock(rpcLock);
status = yp_order(ap->nis_domain_name, singleMap[map_index], &order);
syslock_unlock(rpcLock);
if (status != 0) order = 0;
ap->map_order_number[map_index] = order;
ap->map_order_time[map_index] = now + SERVER_CHECK_LATENCY;
return order;
}
static void
add_validation(dsrecord *r, int map_index, int order)
{
dsdata *d;
dsattribute *a;
char str[32];
if (r == NULL) return;
d = cstring_to_dsdata("lookup_validation");
dsrecord_remove_key(r, d, SELECT_META_ATTRIBUTE);
a = dsattribute_new(d);
dsrecord_append_attribute(r, a, SELECT_META_ATTRIBUTE);
dsdata_release(d);
sprintf(str, "%d %d", map_index, order);
d = cstring_to_dsdata(str);
dsattribute_append(a, d);
dsdata_release(d);
dsattribute_release(a);
}
u_int32_t
NIS_validate(void *c, char *v)
{
agent_private *ap;
int n, vmap, vorder, order;
if (c == NULL) return 0;
if (v == NULL) return 0;
vorder = 0;
vmap = -1;
n = sscanf(v, "%d %d", &vmap, &vorder);
if (n != 2) return 0;
ap = (agent_private *)c;
order = get_order_number(ap, vmap);
if (order != vorder) return 0;
return 1;
}
static dsrecord *
parse(char *data, int cat)
{
if (data == NULL) return NULL;
if (data[0] == '#') return NULL;
switch (cat)
{
case LUCategoryUser: return ff_parse_user(data);
case LUCategoryGroup: return ff_parse_group(data);
case LUCategoryHost: return ff_parse_host(data);
case LUCategoryNetwork: return ff_parse_network(data);
case LUCategoryService: return ff_parse_service(data);
case LUCategoryProtocol: return ff_parse_protocol(data);
case LUCategoryRpc: return ff_parse_rpc(data);
case LUCategoryMount: return ff_parse_mount(data);
case LUCategoryPrinter: return ff_parse_printer(data);
case LUCategoryBootparam: return ff_parse_bootparam(data);
case LUCategoryBootp: return ff_parse_bootp(data);
case LUCategoryAlias: return ff_parse_alias(data);
case LUCategoryNetDomain: return ff_parse_netgroup(data);
case LUCategoryEthernet: return ff_parse_ethernet(data);
case LUCategoryNetgroup: return ff_parse_netgroup(data);
default: return NULL;
}
return NULL;
}
int
map_index_for_key(char *key, LUCategory cat)
{
switch (cat)
{
case LUCategoryUser:
{
if (streq(key, "name")) return 0;
if (streq(key, "uid")) return 1;
return -1;
}
case LUCategoryGroup:
{
if (streq(key, "name")) return 2;
if (streq(key, "gid")) return 3;
return -1;
}
case LUCategoryHost:
{
if (streq(key, "name")) return 4;
if (streq(key, "ip_address")) return 5;
return -1;
}
case LUCategoryNetwork:
{
if (streq(key, "name")) return 6;
if (streq(key, "address")) return 7;
return -1;
}
case LUCategoryService:
{
if (streq(key, "name")) return 8;
return -1;
}
case LUCategoryProtocol:
{
if (streq(key, "name")) return 9;
if (streq(key, "number")) return 10;
return -1;
}
case LUCategoryRpc:
{
if (streq(key, "name")) return 11;
if (streq(key, "number")) return 12;
return -1;
}
case LUCategoryMount:
{
if (streq(key, "name")) return 13;
return -1;
}
case LUCategoryPrinter:
{
if (streq(key, "name")) return 14;
return -1;
}
case LUCategoryBootparam:
{
if (streq(key, "name")) return 15;
return -1;
}
case LUCategoryBootp:
{
if (streq(key, "ip_address")) return 16;
if (streq(key, "en_address")) return 17;
return -1;
}
case LUCategoryAlias:
{
if (streq(key, "name")) return 18;
return -1;
}
case LUCategoryNetgroup:
{
return 19;
}
default:
{
return -1;
}
}
return -1;
}
static int
_NIS_match(agent_private *ap, LUCategory cat, dsdata *k, dsdata *v, dsrecord **list)
{
char *key, *val, *out;
const char *map;
int x, vallen, outlen, order, status;
dsrecord *item = NULL;
time_t now;
key = dsdata_to_cstring(k);
val = dsdata_to_cstring(v);
x = map_index_for_key(key, cat);
if (x == -1) return 1;
map = singleMap[x];
vallen = strlen(val);
out = NULL;
outlen = 0;
now = time(0);
syslock_lock(rpcLock);
status = yp_match(ap->nis_domain_name, map, val, vallen, &out, &outlen);
order = 0;
status = yp_order(ap->nis_domain_name, map, &order);
if (status != 0) order = 0;
ap->map_order_number[x] = order;
ap->map_order_time[x] = now + SERVER_CHECK_LATENCY;
syslock_unlock(rpcLock);
if (status != 0) return 1;
if (out == NULL) return 1;
if (outlen == 0) return 1;
item = parse(out, cat);
free(out);
if (item == NULL) return 1;
add_validation(item, x, order);
*list = item;
return 0;
}
u_int32_t
NIS_query(void *c, dsrecord *pattern, dsrecord **list)
{
agent_private *ap;
u_int32_t cat;
dsattribute *a;
dsdata *k;
dsrecord *lastrec;
char *map;
dsrecord *item = NULL;
int single_item, stamp;
int x, order, status;
char *key, *val, *lastkey, scratch[4096];
int match, keylen, vallen, lastlen;
if (c == NULL) return 1;
if (pattern == NULL) return 1;
if (list == NULL) return 1;
*list = NULL;
lastrec = NULL;
single_item = 0;
stamp = 0;
ap = (agent_private *)c;
k = cstring_to_dsdata(CATEGORY_KEY);
a = dsrecord_attribute(pattern, k, SELECT_META_ATTRIBUTE);
dsdata_release(k);
if (a == NULL) return 1;
if (a->count == 0) return 1;
cat = atoi(dsdata_to_cstring(a->value[0]));
dsattribute_release(a);
x = categoryMapIndex[cat];
map = categoryMap[cat];
if (map == NULL) return 1;
k = cstring_to_dsdata(STAMP_KEY);
a = dsrecord_attribute(pattern, k, SELECT_META_ATTRIBUTE);
dsdata_release(k);
if (a != NULL)
{
dsrecord_remove_attribute(pattern, a, SELECT_META_ATTRIBUTE);
stamp = 1;
}
dsattribute_release(a);
if (stamp == 1)
{
order = get_order_number(ap, x);
item = dsrecord_new();
add_validation(item, x, order);
*list = item;
return 0;
}
a = NULL;
if (cat != LUCategoryService)
{
k = cstring_to_dsdata(SINGLE_KEY);
a = dsrecord_attribute(pattern, k, SELECT_META_ATTRIBUTE);
dsdata_release(k);
}
if (a != NULL)
{
dsattribute_release(a);
single_item = 1;
if ((pattern->count == 1) && (pattern->attribute[0]->count == 1))
{
status = _NIS_match(ap, cat, pattern->attribute[0]->key, pattern->attribute[0]->value[0], list);
return status;
}
}
key = NULL;
val = NULL;
vallen = 0;
lastkey = NULL;
syslock_lock(rpcLock);
order = 0;
status = yp_order(ap->nis_domain_name, map, &order);
if (status != 0) order = 0;
ap->map_order_number[x] = order;
ap->map_order_time[x] = time(0) + SERVER_CHECK_LATENCY;
status = yp_first(ap->nis_domain_name, map, &key, &keylen, &val, &vallen);
if (status != 0)
{
syslock_unlock(rpcLock);
return 1;
}
while (status == 0)
{
switch (cat)
{
case LUCategoryNetgroup:
bcopy(key, scratch, keylen);
scratch[keylen] = ' ';
bcopy(val, scratch+keylen+1, vallen);
scratch[keylen + vallen + 1] = '\0';
break;
case LUCategoryAlias:
bcopy(key, scratch, keylen);
scratch[keylen] = ':';
scratch[keylen + 1] = ' ';
bcopy(val, scratch+keylen+2, vallen);
scratch[keylen + vallen + 2] = '\0';
break;
default:
bcopy(val, scratch, vallen);
scratch[vallen] = '\0';
}
freeString(val);
val = NULL;
vallen = 0;
item = parse(scratch, cat);
freeString(lastkey);
lastkey = NULL;
if (item != NULL)
{
match = dsrecord_match_select(item, pattern, SELECT_ATTRIBUTE);
if (match == 1)
{
add_validation(item, x, order);
if (*list == NULL) *list = dsrecord_retain(item);
else lastrec->next = dsrecord_retain(item);
lastrec = item;
if (single_item == 1)
{
dsrecord_release(item);
break;
}
}
dsrecord_release(item);
}
lastkey = key;
lastlen = keylen;
status = yp_next(ap->nis_domain_name, map, lastkey, lastlen, &key, &keylen, &val, &vallen);
}
syslock_unlock(rpcLock);
freeString(lastkey);
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1