/*
* 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@
*/
/*
* LUServer.m
*
* Lookup server for lookupd
*
* Copyright (c) 1995, NeXT Computer Inc.
* All rights reserved.
* Written by Marc Majka
*/
#import <NetInfo/system_log.h>
#import <NetInfo/syslock.h>
#import "LUServer.h"
#import "LUCachedDictionary.h"
#import "LUPrivate.h"
#import "Controller.h"
#import "Config.h"
#import <NetInfo/dsutil.h>
#import <string.h>
#import <stdlib.h>
#import <stdio.h>
#define MaxNetgroupRecursion 5
#define XDRSIZE 8192
#define MICROSECONDS 1000000
#define MILLISECONDS 1000
static unsigned int
milliseconds_since(struct timeval t)
{
struct timeval now, delta;
unsigned int millisec;
gettimeofday(&now, NULL);
delta.tv_sec = now.tv_sec - t.tv_sec;
if (t.tv_usec > now.tv_usec)
{
now.tv_usec += 1000000;
delta.tv_sec -= 1;
}
delta.tv_usec = now.tv_usec - t.tv_usec;
millisec = ((delta.tv_sec * 1000000) + delta.tv_usec) / 1000;
return millisec;
}
@implementation LUServer
+ (LUServer *)alloc
{
id s;
s = [super alloc];
system_log(LOG_DEBUG, "Allocated LUServer 0x
return s;
}
- (char **)lookupOrderForCategory:(LUCategory)cat
{
LUDictionary *cdict;
char **order;
cdict = [configManager configForCategory:cat fromConfig:configurationArray];
if (cdict != nil)
{
order = [cdict valuesForKey:"LookupOrder"];
if (order != NULL) return order;
}
cdict = [configManager configGlobal:configurationArray];
if (cdict == nil) return NULL;
order = [cdict valuesForKey:"LookupOrder"];
return order;
}
- (LUServer *)init
{
[super init];
agentList = [[LUArray alloc] init];
[agentList setBanner:"LUServer agent list"];
ooBufferSize = 0;
ooBufferOffset = 0;
ooBuffer = NULL;
idle = YES;
state = ServerStateIdle;
currentAgent = nil;
currentCall = NULL;
return self;
}
- (BOOL)isIdle
{
return idle;
}
/*
* Called on check out / check in.
*/
- (void)setIsIdle:(BOOL)yn
{
Thread *t;
t = [Thread currentThread];
if (yn)
{
if (t != myThread)
{
system_log(LOG_ERR, "Thread return;
}
idle = YES;
state = ServerStateIdle;
myThread = nil;
if (ooBufferSize > 0)
{
free(ooBuffer);
ooBuffer = NULL;
ooBufferSize = 0;
ooBufferOffset = 0;
}
}
else
{
if (myThread != nil)
{
system_log(LOG_ERR, "Thread return;
}
idle = NO;
state = ServerStateActive;
myThread = t;
}
}
- (LUAgent *)agentNamed:(char *)name
{
id agentClass;
char *arg, *colon, *cname, *cserv;
int i, len;
id agent;
if (name == NULL) return nil;
arg = NULL;
colon = strchr(name, ':');
if (colon != NULL)
{
*colon = '\0';
arg = colon + 1;
}
cname = NULL;
len = strlen(name);
if (len > 5)
{
if (streq(name + (len - 5), "Agent"))
{
cname = copyString(name);
}
}
if (cname == NULL)
{
cname = malloc(len + 6);
sprintf(cname, " }
if (colon != NULL) *colon = ':';
cserv = NULL;
if (arg == NULL)
{
cserv = copyString(cname);
}
else
{
cserv = malloc(strlen(cname) + strlen(arg) + 2);
sprintf(cserv, " }
len = [agentList count];
for (i = 0; i < len; i++)
{
agent = [agentList objectAtIndex:i];
if (streq([agent serviceName], cserv))
{
free(cname);
free(cserv);
return agent;
}
}
agentClass = [controller agentClassNamed:cname];
free(cname);
free(cserv);
if (agentClass == NULL) return nil;
agent = nil;
if (arg == NULL) agent = [[agentClass alloc] init];
else agent = [[agentClass alloc] initWithArg:arg];
if (agent == nil) return nil;
[agentList addObject:agent];
[agent release];
system_log(LOG_DEBUG, "LUServer 0x (int)self, (int)agent, [agent serviceName]);
return agent;
}
- (void)copyToOOBuffer:(char *)src size:(unsigned long)len
{
long avail, delta;
if (ooBufferSize == 0)
{
ooBufferSize = XDRSIZE * ((len / XDRSIZE) + 1);
ooBuffer = malloc(ooBufferSize);
ooBufferOffset = 0;
}
else
{
avail = ooBufferSize - ooBufferOffset;
if (len > avail)
{
delta = XDRSIZE * (((len - avail) / XDRSIZE) + 1);
ooBufferSize += delta;
ooBuffer = realloc(ooBuffer, ooBufferSize);
}
}
memmove(ooBuffer + ooBufferOffset, src, len);
ooBufferOffset += len;
}
- (char *)ooBuffer
{
return ooBuffer;
}
- (int)ooBufferLength
{
return (int)ooBufferOffset;
}
- (void)dealloc
{
int i, len;
LUAgent *agent;
if (agentList != nil)
{
len = [agentList count];
for (i = len - 1; i >= 0; i--)
{
agent = [agentList objectAtIndex:i];
system_log(LOG_DEBUG, " [agentList removeObject:agent];
}
[agentList release];
}
free(ooBuffer);
system_log(LOG_DEBUG, "Deallocated LUServer 0x
[super dealloc];
}
- (void)addTime:(unsigned int)t hit:(BOOL)found forKey:(const char *)key
{
unsigned long calls, time, hits;
char str[128], *v;
if (key == NULL) return;
calls = 0;
time = 0;
hits = 0;
syslock_lock(statsLock);
v = [statistics valueForKey:(char *)key];
if (v != NULL) sscanf(v, "
calls += 1;
if (found) hits += 1;
time += t;
sprintf(str, " [statistics setValue:str forKey:(char *)key];
syslock_unlock(statsLock);
}
- (void)recordCall:(char *)method time:(unsigned int)t hit:(BOOL)found
{
/* total of all calls */
[self addTime:t hit:found forKey:"total"];
/* total calls of this lookup method */
[self addTime:t hit:found forKey:method];
}
- (void)recordSearch:(char *)method
infoSystem:(const char *)info
time:(unsigned int)t
hit:(BOOL)found
{
char key[256];
/* total for this info system */
[self addTime:t hit:found forKey:info];
/* total for this method in this info system */
sprintf(key, " [self addTime:t hit:found forKey:key];
}
- (LUDictionary *)stamp:(LUDictionary *)item
agent:(LUAgent *)agent
category:(LUCategory)cat
{
BOOL cacheEnabled;
char scratch[256];
if (item == nil) return nil;
cacheEnabled = [cacheAgent cacheIsEnabledForCategory:cat];
[item setCategory:cat];
if (strcmp([agent shortName], "Cache"))
{
if (cat == LUCategoryBootp)
{
sprintf(scratch, " [agent shortName],
[LUAgent categoryName:cat],
[item valueForKey:"name"],
[item valueForKey:"en_address"],
[item valueForKey:"ip_address"]);
}
else
{
sprintf(scratch, " [agent shortName],
[LUAgent categoryName:cat],
[item valueForKey:"name"]);
}
[item setBanner:scratch];
}
if (cacheEnabled && (strcmp([agent shortName], "Cache")))
{
[cacheAgent addObject:item];
}
if ([item isNegative])
{
[item release];
return nil;
}
return item;
}
- (unsigned long)state
{
return state;
}
- (LUAgent *)currentAgent
{
return currentAgent;
}
- (char *)currentCall
{
return currentCall;
}
static char *
appendDomainName(char *h, char *d)
{
int len;
char *q;
if (h == NULL) return NULL;
if (d == NULL) return copyString(h);
len = strlen(h) + strlen(d) + 2;
q = malloc(len);
sprintf(q, " return q;
}
/*
* Given a host name, returns a list of possible variations
* based on our DNS domain name / DNS domain search list.
*/
- (char **)hostNameList:(char *)host
{
char **l, **dns;
char *p, *s;
int i, len;
if (host == NULL) return NULL;
/* Bail out if we are shutting down (prevents a call to controller) */
if (shutting_down) return NULL;
l = NULL;
l = appendString(host, l);
dns = [controller dnsSearchList];
/* If no DNS, list is just (host) */
if (dns == NULL) return l;
len = listLength(dns);
p = strchr(host, '.');
if (p == NULL)
{
/*
* Unqualified host name.
* Return (host, host.<dns[0]>, host.<dns[1]>, ...)
*/
for (i = 0; i < len; i++)
{
s = appendDomainName(host, dns[i]);
if (s == NULL) continue;
l = appendString(s, l);
free(s);
}
return l;
}
/*
* Hostname is qualified.
* If domain is in dns search list, we return (host.domain, host).
* Otherwise, return (host.domain).
*/
for (i = 0; i < len; i++)
{
if (streq(p+1, dns[i]))
{
/* Strip domain name, append host to list */
*p = '\0';
l = appendString(host, l);
*p = '.';
return l;
}
}
return l;
}
- (LUArray *)allItemsWithCategory:(LUCategory)cat
{
char **lookupOrder;
LUArray *all;
LUArray *sub;
LUAgent *agent;
LUDictionary *stamp;
LUDictionary *item;
int i, len;
int j, sublen;
BOOL cacheEnabled, found;
char scratch[256], caller[256];
struct timeval allStart;
struct timeval sysStart;
unsigned int sysTime;
unsigned int allTime;
if (cat >= NCATEGORIES) return nil;
gettimeofday(&allStart, (struct timezone *)NULL);
sprintf(caller, "all currentCall = caller;
cacheEnabled = [cacheAgent cacheIsEnabledForCategory:cat];
if (cacheEnabled)
{
gettimeofday(&sysStart, (struct timezone *)NULL);
currentAgent = cacheAgent;
state = ServerStateQuerying;
all = [cacheAgent allItemsWithCategory:cat];
state = ServerStateActive;
currentAgent = nil;
sysTime = milliseconds_since(sysStart);
found = (all != nil);
[self recordSearch:caller infoSystem:"Cache" time:sysTime hit:found];
if (found)
{
allTime = milliseconds_since(allStart);
[self recordCall:caller time:allTime hit:found];
currentCall = NULL;
return all;
}
}
all = [[LUArray alloc] init];
lookupOrder = [self lookupOrderForCategory:cat];
len = listLength(lookupOrder);
agent = nil;
for (i = 0; i < len; i++)
{
agent = [self agentNamed:lookupOrder[i]];
if (agent == nil) continue;
if (streq([agent shortName], "Cache")) continue;
gettimeofday(&sysStart, (struct timezone *)NULL);
currentAgent = agent;
state = ServerStateQuerying;
sub = [agent allItemsWithCategory:cat];
state = ServerStateActive;
currentAgent = nil;
sysTime = milliseconds_since(sysStart);
found = (sub != nil);
[self recordSearch:caller infoSystem:[agent shortName] time:sysTime hit:found];
if (found)
{
/* Merge validation info from this agent into "all" array */
sublen = [sub validationStampCount];
for (j = 0; j < sublen; j++)
{
stamp = [sub validationStampAtIndex:j];
[stamp setCategory:cat];
[all addValidationStamp:stamp];
}
sublen = [sub count];
for (j = 0; j < sublen; j++)
{
item = [sub objectAtIndex:j];
[item setCategory:cat];
[all addObject:item];
}
[sub release];
}
}
allTime = milliseconds_since(allStart);
found = ([all count] != 0);
[self recordCall:caller time:allTime hit:found];
if (!found)
{
[all release];
currentCall = NULL;
return nil;
}
sprintf(scratch, "LUServer: all [all setBanner:scratch];
if (cacheEnabled) [cacheAgent addArray:all];
currentCall = NULL;
return all;
}
- (LUArray *)query:(LUDictionary *)pattern
{
char **lookupOrder;
LUArray *all, *list;
LUArray *sub;
LUAgent *agent;
LUDictionary *item;
LUCategory cat;
int i, len;
int j, sublen;
BOOL found;
char caller[256], *pagent;
struct timeval listStart;
struct timeval sysStart;
unsigned int sysTime;
unsigned int listTime;
unsigned int where;
if (pattern == nil) return nil;
where = [pattern indexForKey:"_lookup_category"];
if (where == IndexNull) return nil;
cat = [LUAgent categoryWithName:[pattern valueAtIndex:where]];
if (cat > NCATEGORIES) return nil;
pagent = NULL;
where = [pattern indexForKey:"_lookup_agent"];
if (where != IndexNull) pagent = [pattern valueAtIndex:where];
gettimeofday(&listStart, (struct timezone *)NULL);
sprintf(caller, "query");
currentCall = caller;
if ((pagent != NULL) && (!strcmp(pagent, "Cache")))
{
gettimeofday(&sysStart, (struct timezone *)NULL);
currentAgent = cacheAgent;
state = ServerStateQuerying;
list = nil;
all = [cacheAgent allItemsWithCategory:cat];
if (all != nil)
{
list = [all filter:pattern];
[all release];
}
state = ServerStateActive;
currentAgent = nil;
sysTime = milliseconds_since(sysStart);
found = (list != nil);
[self recordSearch:caller infoSystem:"Cache" time:sysTime hit:found];
listTime = milliseconds_since(listStart);
[self recordCall:caller time:listTime hit:found];
currentCall = NULL;
return list;
}
all = [[LUArray alloc] init];
lookupOrder = [self lookupOrderForCategory:cat];
len = listLength(lookupOrder);
agent = nil;
for (i = 0; i < len; i++)
{
agent = [self agentNamed:lookupOrder[i]];
if (agent == nil) continue;
if (streq([agent shortName], "Cache")) continue;
if ((pagent != NULL) && strcmp([agent shortName], pagent)) continue;
gettimeofday(&sysStart, (struct timezone *)NULL);
currentAgent = agent;
state = ServerStateQuerying;
sub = [agent query:pattern category:cat];
state = ServerStateActive;
currentAgent = nil;
sysTime = milliseconds_since(sysStart);
found = (sub != nil);
[self recordSearch:caller infoSystem:[agent shortName] time:sysTime hit:found];
if (found)
{
sublen = [sub count];
for (j = 0; j < sublen; j++)
{
item = [sub objectAtIndex:j];
[item setCategory:cat];
[all addObject:item];
}
[sub release];
}
}
listTime = milliseconds_since(listStart);
found = ([all count] != 0);
[self recordCall:caller time:listTime hit:found];
if (!found)
{
[all release];
currentCall = NULL;
return nil;
}
currentCall = NULL;
return all;
}
- (LUArray *)allGroupsWithUser:(char *)name
{
char **lookupOrder;
LUArray *all;
LUArray *sub;
LUAgent *agent;
LUDictionary *stamp;
int i, len;
int j, sublen;
BOOL cacheEnabled, found;
char scratch[256];
struct timeval allStart;
struct timeval sysStart;
unsigned int sysTime;
unsigned int allTime;
currentCall = "initgroups";
if (name == NULL)
{
[self recordSearch:currentCall infoSystem:"Failed" time:0 hit:YES];
[self recordCall:currentCall time:0 hit:NO];
currentCall = NULL;
return nil;
}
gettimeofday(&allStart, (struct timezone *)NULL);
cacheEnabled = [cacheAgent cacheIsEnabledForCategory:LUCategoryInitgroups];
if (cacheEnabled)
{
gettimeofday(&sysStart, (struct timezone *)NULL);
currentAgent = cacheAgent;
state = ServerStateQuerying;
all = [cacheAgent initgroupsForUser:name];
state = ServerStateActive;
currentAgent = nil;
sysTime = milliseconds_since(sysStart);
found = (all != nil);
[self recordSearch:currentCall infoSystem:"Cache"
time:sysTime hit:found];
if (found)
{
allTime = milliseconds_since(allStart);
[self recordCall:currentCall time:allTime hit:found];
currentCall = NULL;
return all;
}
}
all = [[LUArray alloc] init];
lookupOrder = [self lookupOrderForCategory:LUCategoryUser];
len = listLength(lookupOrder);
agent = nil;
for (i = 0; i < len; i++)
{
agent = [self agentNamed:lookupOrder[i]];
if (agent == nil) continue;
if (streq([agent shortName], "Cache")) continue;
gettimeofday(&sysStart, (struct timezone *)NULL);
currentAgent = agent;
state = ServerStateQuerying;
sub = [agent allGroupsWithUser:name];
state = ServerStateActive;
currentAgent = nil;
sysTime = milliseconds_since(sysStart);
found = (sub != nil);
[self recordSearch:currentCall infoSystem:[agent shortName]
time:sysTime hit:found];
if (found)
{
/* Merge validation info from this agent into "all" array */
sublen = [sub validationStampCount];
for (j = 0; j < sublen; j++)
{
stamp = [sub validationStampAtIndex:j];
[stamp setCategory:LUCategoryInitgroups];
[all addValidationStamp:stamp];
}
sublen = [sub count];
for (j = 0; j < sublen; j++)
{
[all addObject:[sub objectAtIndex:j]];
}
[sub release];
}
}
allTime = milliseconds_since(allStart);
found = ([all count] != 0);
[self recordCall:currentCall time:allTime hit:found];
if (!found)
{
[all release];
currentCall = NULL;
return nil;
}
sprintf(scratch, "LUServer: all groups with user [all setBanner:scratch];
if (cacheEnabled) [cacheAgent setInitgroups:all forUser:name];
currentCall = NULL;
return all;
}
- (LUArray *)allNetgroupsWithName:(char *)name
{
LUArray *all;
char **lookupOrder;
LUDictionary *item;
LUAgent *agent;
int i, len;
char scratch[256];
struct timeval allStart;
struct timeval sysStart;
unsigned int sysTime;
unsigned int allTime;
BOOL found;
currentCall = "netgroup name";
if (name == NULL)
{
[self recordSearch:currentCall infoSystem:"Failed" time:0 hit:YES];
[self recordCall:currentCall time:0 hit:NO];
currentCall = NULL;
return nil;
}
lookupOrder = [self lookupOrderForCategory:LUCategoryNetgroup];
len = listLength(lookupOrder);
if (len == 0)
{
currentCall = NULL;
return nil;
}
all = [[LUArray alloc] init];
gettimeofday(&allStart, (struct timezone *)NULL);
for (i = 0; i < len; i++)
{
agent = [self agentNamed:lookupOrder[i]];
if (agent == nil) continue;
gettimeofday(&sysStart, (struct timezone *)NULL);
currentAgent = agent;
state = ServerStateQuerying;
item = [agent itemWithKey:"name" value:name category:LUCategoryNetgroup];
state = ServerStateActive;
currentAgent = nil;
sysTime = milliseconds_since(sysStart);
found = (item != nil);
[self recordSearch:currentCall infoSystem:[agent shortName]
time:sysTime hit:found];
if (found)
{
[all addObject:item];
[item release];
}
}
allTime = milliseconds_since(allStart);
found = ([all count] != 0);
[self recordCall:currentCall time:allTime hit:found];
if (!found)
{
[all release];
currentCall = NULL;
return nil;
}
sprintf(scratch, "LUServer: all netgroup [all setBanner:scratch];
currentCall = NULL;
return all;
}
- (LUDictionary *)groupWithKey:(char *)key value:(char *)val
{
LUArray *all;
char **lookupOrder;
LUDictionary *item;
int i, len;
char scratch[256];
char str[1024];
struct timeval allStart;
struct timeval sysStart;
unsigned int sysTime;
unsigned int allTime;
BOOL found, cacheEnabled;
LUDictionary *q;
if (key == NULL) return nil;
if (val == NULL) return nil;
sprintf(str, " currentCall = str;
lookupOrder = [self lookupOrderForCategory:LUCategoryGroup];
item = nil;
len = listLength(lookupOrder);
gettimeofday(&allStart, (struct timezone *)NULL);
cacheEnabled = [cacheAgent cacheIsEnabledForCategory:LUCategoryGroup];
if (cacheEnabled)
{
gettimeofday(&sysStart, (struct timezone *)NULL);
currentAgent = cacheAgent;
state = ServerStateQuerying;
item = [cacheAgent itemWithKey:key value:val category:LUCategoryGroup];
state = ServerStateActive;
currentAgent = nil;
sysTime = milliseconds_since(sysStart);
found = (item != nil);
[self recordSearch:currentCall infoSystem:"Cache" time:sysTime hit:found];
if (found)
{
allTime = milliseconds_since(allStart);
[self recordCall:currentCall time:allTime hit:found];
currentCall = NULL;
return item;
}
}
q = [[LUDictionary alloc] init];
[q setValue:val forKey:key];
[q setValue:"group" forKey:"_lookup_category"];
all = [self query:q];
[q release];
if (all == nil) return nil;
item = [[LUDictionary alloc] init];
[item setCategory:LUCategoryGroup];
sprintf(scratch, "LUServer: group [item setBanner:scratch];
len = [all count];
for (i = 0; i < len; i++)
{
[item mergeKey:"name" from:[all objectAtIndex:i]];
[item mergeKey:"gid" from:[all objectAtIndex:i]];
[item mergeKey:"users" from:[all objectAtIndex:i]];
}
[all release];
if (cacheEnabled) [cacheAgent addObject:item];
return item;
}
- (LUDictionary *)netgroupWithName:(char *)name
{
LUArray *all;
LUDictionary *group;
int i, len;
char scratch[256];
if (name == NULL) return nil;
all = [self allNetgroupsWithName:name];
if (all == nil) return nil;
group = [[LUDictionary alloc] init];
sprintf(scratch, "LUServer: netgroup [group setBanner:scratch];
[group setValue:name forKey:"name"];
len = [all count];
for (i = 0; i < len; i++)
[self mergeNetgroup:[all objectAtIndex:i] into:group];
[all release];
return group;
}
/*
* This is the search routine for itemWithKey:value:category
*/
- (LUDictionary *)findItemWithKey:(char *)key
value:(char *)val
category:(LUCategory)cat
{
char **lookupOrder;
LUDictionary *item;
LUAgent *agent;
int i, j, len, nether;
char **etherAddrs;
struct timeval allStart;
struct timeval sysStart;
unsigned int sysTime;
unsigned int allTime;
char str[1024];
BOOL tryRealName, isEtherAddr, found;
sprintf(str, " currentCall = str;
lookupOrder = [self lookupOrderForCategory:cat];
item = nil;
len = listLength(lookupOrder);
tryRealName = NO;
if ((cat == LUCategoryUser) && (streq(key, "name"))) tryRealName = YES;
isEtherAddr = NO;
if (streq(key, "en_address")) isEtherAddr = YES;
gettimeofday(&allStart, (struct timezone *)NULL);
for (i = 0; i < len; i++)
{
agent = [self agentNamed:lookupOrder[i]];
if (agent == nil) continue;
gettimeofday(&sysStart, (struct timezone *)NULL);
currentAgent = agent;
state = ServerStateQuerying;
if (isEtherAddr)
{
/* Try all possible variations on leading zeros in the address */
etherAddrs = [LUAgent variationsOfEthernetAddress:val];
nether = listLength(etherAddrs);
for (j = 0; j < nether; j++)
{
item = [agent itemWithKey:key value:etherAddrs[j] category:cat];
if (item != nil) break;
}
freeList(etherAddrs);
}
else
{
item = [agent itemWithKey:key value:val category:cat];
if (tryRealName && (item == nil) && strcmp([agent shortName], "NI"))
{
item = [agent itemWithKey:"realname" value:val category:cat];
}
}
state = ServerStateActive;
currentAgent = nil;
sysTime = milliseconds_since(sysStart);
found = (item != nil);
[self recordSearch:currentCall infoSystem:[agent shortName] time:sysTime hit:found];
if (found)
{
allTime = milliseconds_since(allStart);
[self recordCall:currentCall time:allTime hit:found];
currentCall = NULL;
return [self stamp:item agent:agent category:cat];
}
}
allTime = milliseconds_since(allStart);
[self recordSearch:currentCall infoSystem:"Failed" time:allTime hit:YES];
[self recordCall:currentCall time:allTime hit:NO];
currentCall = NULL;
return nil;
}
- (void)preferBootpAddress:(char *)addr
key:(char *)key
target:(char *)tkey
dict:(LUDictionary *)dict
{
char **kVals, **tVals;
char *t;
int i, target, kLen, tLen, tLast;
kVals = [dict valuesForKey:key];
tVals = [dict valuesForKey:tkey];
tLen = listLength(tVals);
if (tLen == 0) return;
kLen = listLength(kVals);
if (kLen == 0) return;
tLast = tLen - 1;
target = 0;
for (i = 0; i < kLen; i++)
{
if (i == tLast) break;
if (streq(addr, kVals[i]))
{
target = i;
break;
}
}
[dict removeKey:key];
[dict setValue:addr forKey:key];
t = copyString(tVals[target]);
[dict removeKey:tkey];
[dict setValue:t forKey:tkey];
freeString(t);
}
/*
* Find an item. This method handles some special cases.
* It calls findItemWithKey:value:category to do the work.
*/
- (LUDictionary *)itemWithKey:(char *)key
value:(char *)val
category:(LUCategory)cat
{
LUDictionary *item;
if ((key == NULL) || (val == NULL) || (cat > NCATEGORIES))
{
return nil;
}
if (cat == LUCategoryGroup)
{
return [self groupWithKey:key value:val];
}
if (cat == LUCategoryNetgroup)
{
return [self netgroupWithName:val];
}
if (streq(key, "en_address")) val = [LUAgent canonicalEthernetAddress:val];
item = [self findItemWithKey:key value:val category:cat];
if ((cat == LUCategoryBootp) && (item != nil))
{
if (streq(key, "ip_address"))
{
/* only return a directory if there is an en_address */
if ([item valuesForKey:"en_address"] == NULL)
{
[item release];
return nil;
}
[self preferBootpAddress:val key:key target:"en_address" dict:item];
}
else if (streq(key, "en_address"))
{
[self preferBootpAddress:val key:key target:"ip_address" dict:item];
}
}
return item;
}
- (BOOL)inNetgroup:(char *)group
host:(char *)host
user:(char *)user
domain:(char *)domain
level:(int)level
{
LUDictionary *g;
int i, len;
char **members;
char *name;
if (level > MaxNetgroupRecursion)
{
system_log(LOG_ERR, "netgroups nested more than MaxNetgroupRecursion);
return NO;
}
if (group == NULL) return NO;
g = [self itemWithKey:"name" value:group category:LUCategoryNetgroup];
if (g == nil) return NO;
if (host != NULL)
{
name = host;
members = [g valuesForKey:"hosts"];
}
else if (user != NULL)
{
name = user;
members = [g valuesForKey:"users"];
}
else if (domain != NULL)
{
name = domain;
members = [g valuesForKey:"domains"];
}
else
{
[g release];
return NO;
}
if ((listIndex("*", members) != IndexNull) ||
(listIndex(name, members) != IndexNull))
{
[g release];
return YES;
}
members = [g valuesForKey:"netgroups"];
len = [g countForKey:"netgroups"];
for (i = 0; i < len; i++)
{
if ([self inNetgroup:members[i] host:host user:user domain:domain
level:level+1])
{
[g release];
return YES;
}
}
[g release];
return NO;
}
- (BOOL)inNetgroup:(char *)group
host:(char *)host
user:(char *)user
domain:(char *)domain
{
char **nameList;
int i, len;
BOOL yn;
nameList = [self hostNameList:host];
len = listLength(nameList);
for (i = 0; i < len; i++)
{
yn = [self inNetgroup:group host:nameList[i] user:user domain:domain level:0];
if (yn == YES)
{
freeList(nameList);
return YES;
}
}
freeList(nameList);
return NO;
}
- (LUDictionary *)serviceWithName:(char *)name
protocol:(char *)prot
{
char **lookupOrder;
LUDictionary *item;
LUAgent *agent;
int i, len;
struct timeval allStart;
struct timeval sysStart;
unsigned int sysTime;
unsigned int allTime;
BOOL found;
currentCall = "service name";
if (name == NULL)
{
[self recordSearch:currentCall infoSystem:"Failed" time:0 hit:YES];
[self recordCall:currentCall time:0 hit:NO];
currentCall = NULL;
return nil;
}
gettimeofday(&allStart, (struct timezone *)NULL);
lookupOrder = [self lookupOrderForCategory:LUCategoryService];
item = nil;
len = listLength(lookupOrder);
for (i = 0; i < len; i++)
{
agent = [self agentNamed:lookupOrder[i]];
if (agent == nil) continue;
gettimeofday(&sysStart, (struct timezone *)NULL);
currentAgent = agent;
state = ServerStateQuerying;
item = [agent serviceWithName:name protocol:prot];
state = ServerStateActive;
currentAgent = nil;
sysTime = milliseconds_since(sysStart);
found = (item != nil);
[self recordSearch:currentCall infoSystem:[agent shortName]
time:sysTime hit:found];
if (found)
{
allTime = milliseconds_since(allStart);
[self recordCall:currentCall time:allTime hit:found];
currentCall = NULL;
return [self stamp:item agent:agent category:LUCategoryService];
}
}
allTime = milliseconds_since(allStart);
[self recordSearch:currentCall infoSystem:"Failed" time:allTime hit:YES];
[self recordCall:currentCall time:allTime hit:NO];
currentCall = NULL;
return nil;
}
- (LUDictionary *)serviceWithNumber:(int *)number
protocol:(char *)prot
{
char **lookupOrder;
LUDictionary *item;
LUAgent *agent;
int i, len;
struct timeval allStart;
struct timeval sysStart;
unsigned int sysTime;
unsigned int allTime;
BOOL found;
currentCall = "service number";
if (number == NULL)
{
[self recordSearch:currentCall infoSystem:"Failed" time:0 hit:YES];
[self recordCall:currentCall time:0 hit:NO];
currentCall = NULL;
return nil;
}
gettimeofday(&allStart, (struct timezone *)NULL);
lookupOrder = [self lookupOrderForCategory:LUCategoryService];
item = nil;
len = listLength(lookupOrder);
for (i = 0; i < len; i++)
{
agent = [self agentNamed:lookupOrder[i]];
if (agent == nil) continue;
gettimeofday(&sysStart, (struct timezone *)NULL);
currentAgent = agent;
state = ServerStateQuerying;
item = [agent serviceWithNumber:number protocol:prot];
state = ServerStateActive;
currentAgent = nil;
sysTime = milliseconds_since(sysStart);
found = (item != nil);
[self recordSearch:currentCall infoSystem:[agent shortName]
time:sysTime hit:found];
if (found)
{
allTime = milliseconds_since(allStart);
[self recordCall:currentCall time:allTime hit:found];
currentCall = NULL;
return [self stamp:item agent:agent category:LUCategoryService];
}
}
allTime = milliseconds_since(allStart);
[self recordSearch:currentCall infoSystem:"Failed" time:allTime hit:YES];
[self recordCall:currentCall time:allTime hit:NO];
currentCall = NULL;
return nil;
}
- (BOOL)isSecurityEnabledForOption:(char *)option
{
NIAgent *ni;
ni = (NIAgent *)[self agentNamed:"NIAgent"];
if (ni == nil) return NO;
/* XXX */
return [ni isSecurityEnabledForOption:option];
}
- (BOOL)isNetwareEnabled
{
return NO;
}
@end