/* * 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 #include #ifdef RPC_SUCCESS #undef RPC_SUCCESS #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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; }