1*cf1d77f7Schristos /*	$NetBSD: nssov.c,v 1.3 2021/08/14 16:14:52 christos Exp $	*/
24e6df137Slukem 
3bb30016cSlukem /* nssov.c - nss-ldap overlay for slapd */
433197c6aStron /* $OpenLDAP$ */
54e6df137Slukem /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
64e6df137Slukem  *
7*cf1d77f7Schristos  * Copyright 2008-2021 The OpenLDAP Foundation.
84e6df137Slukem  * Portions Copyright 2008 by Howard Chu, Symas Corp.
933197c6aStron  * Portions Copyright 2013 by Ted C. Cheng, Symas Corp.
10bb30016cSlukem  * All rights reserved.
11bb30016cSlukem  *
12bb30016cSlukem  * Redistribution and use in source and binary forms, with or without
13bb30016cSlukem  * modification, are permitted only as authorized by the OpenLDAP
14bb30016cSlukem  * Public License.
15bb30016cSlukem  *
16bb30016cSlukem  * A copy of this license is available in the file LICENSE in the
17bb30016cSlukem  * top-level directory of the distribution or, alternatively, at
18bb30016cSlukem  * <http://www.OpenLDAP.org/license.html>.
19bb30016cSlukem  */
204e6df137Slukem /* ACKNOWLEDGEMENTS:
21bb30016cSlukem  * This code references portions of the nss-ldapd package
22bb30016cSlukem  * written by Arthur de Jong. The nss-ldapd code was forked
23bb30016cSlukem  * from the nss-ldap library written by Luke Howard.
24bb30016cSlukem  */
25bb30016cSlukem 
26bb30016cSlukem #include "nssov.h"
27bb30016cSlukem 
28bb30016cSlukem #ifndef SLAPD_OVER_NSSOV
29bb30016cSlukem #define SLAPD_OVER_NSSOV SLAPD_MOD_DYNAMIC
30bb30016cSlukem #endif
31bb30016cSlukem 
32*cf1d77f7Schristos #include "slap-config.h"
33bb30016cSlukem 
34bb30016cSlukem #include "lutil.h"
35bb30016cSlukem 
36bb30016cSlukem #include <ac/errno.h>
37bb30016cSlukem #include <ac/unistd.h>
38bb30016cSlukem #include <fcntl.h>
39bb30016cSlukem #include <sys/stat.h>
40bb30016cSlukem 
414e6df137Slukem AttributeDescription *nssov_pam_host_ad;
424e6df137Slukem AttributeDescription *nssov_pam_svc_ad;
434e6df137Slukem 
44bb30016cSlukem /* buffer sizes for I/O */
45bb30016cSlukem #define READBUFFER_MINSIZE 32
46bb30016cSlukem #define READBUFFER_MAXSIZE 64
47bb30016cSlukem #define WRITEBUFFER_MINSIZE 64
48bb30016cSlukem #define WRITEBUFFER_MAXSIZE 64*1024
49bb30016cSlukem 
50bb30016cSlukem /* Find the given attribute's value in the RDN of the DN */
nssov_find_rdnval(struct berval * dn,AttributeDescription * ad,struct berval * value)518bd9f7cdSchristos void nssov_find_rdnval(struct berval *dn, AttributeDescription *ad, struct berval *value)
52bb30016cSlukem {
53bb30016cSlukem 	struct berval rdn;
54bb30016cSlukem 	char *next;
55bb30016cSlukem 
56bb30016cSlukem 	BER_BVZERO(value);
57bb30016cSlukem 	dnRdn( dn, &rdn );
58bb30016cSlukem 	do {
59bb30016cSlukem 		next = ber_bvchr( &rdn, '+' );
60bb30016cSlukem 		if ( rdn.bv_val[ad->ad_cname.bv_len] == '=' &&
61bb30016cSlukem 			!ber_bvcmp( &rdn, &ad->ad_cname )) {
62bb30016cSlukem 			if ( next )
63bb30016cSlukem 				rdn.bv_len = next - rdn.bv_val;
64bb30016cSlukem 			value->bv_val = rdn.bv_val + ad->ad_cname.bv_len + 1;
65bb30016cSlukem 			value->bv_len = rdn.bv_len - ad->ad_cname.bv_len - 1;
66bb30016cSlukem 			break;
67bb30016cSlukem 		}
68bb30016cSlukem 		if ( !next )
69bb30016cSlukem 			break;
70bb30016cSlukem 		next++;
71bb30016cSlukem 		rdn.bv_len -= next - rdn.bv_val;
72bb30016cSlukem 		rdn.bv_val = next;
73bb30016cSlukem 	} while (1);
74bb30016cSlukem }
75bb30016cSlukem 
76bb30016cSlukem /* create a search filter using a name that requires escaping */
nssov_filter_byname(nssov_mapinfo * mi,int key,struct berval * name,struct berval * buf)77bb30016cSlukem int nssov_filter_byname(nssov_mapinfo *mi,int key,struct berval *name,struct berval *buf)
78bb30016cSlukem {
79bb30016cSlukem 	char buf2[1024];
80bb30016cSlukem 	struct berval bv2 = {sizeof(buf2),buf2};
81bb30016cSlukem 
82bb30016cSlukem 	/* escape attribute */
83bb30016cSlukem 	if (nssov_escape(name,&bv2))
84bb30016cSlukem 		return -1;
85bb30016cSlukem 	/* build filter */
86bb30016cSlukem 	if (bv2.bv_len + mi->mi_filter.bv_len + mi->mi_attrs[key].an_desc->ad_cname.bv_len + 6 >
87bb30016cSlukem 		buf->bv_len )
88bb30016cSlukem 		return -1;
89bb30016cSlukem 	buf->bv_len = snprintf(buf->bv_val, buf->bv_len, "(&%s(%s=%s))",
90bb30016cSlukem 		mi->mi_filter.bv_val, mi->mi_attrs[key].an_desc->ad_cname.bv_val,
91bb30016cSlukem 		bv2.bv_val );
92bb30016cSlukem 	return 0;
93bb30016cSlukem }
94bb30016cSlukem 
95bb30016cSlukem /* create a search filter using a string converted from an int */
nssov_filter_byid(nssov_mapinfo * mi,int key,struct berval * id,struct berval * buf)96bb30016cSlukem int nssov_filter_byid(nssov_mapinfo *mi,int key,struct berval *id,struct berval *buf)
97bb30016cSlukem {
98bb30016cSlukem 	/* build filter */
99bb30016cSlukem 	if (id->bv_len + mi->mi_filter.bv_len + mi->mi_attrs[key].an_desc->ad_cname.bv_len + 6 >
100bb30016cSlukem 		buf->bv_len )
101bb30016cSlukem 		return -1;
102bb30016cSlukem 	buf->bv_len = snprintf(buf->bv_val, buf->bv_len, "(&%s(%s=%s))",
103bb30016cSlukem 		mi->mi_filter.bv_val, mi->mi_attrs[key].an_desc->ad_cname.bv_val,
104bb30016cSlukem 		id->bv_val );
105bb30016cSlukem 	return 0;
106bb30016cSlukem }
107bb30016cSlukem 
get_userpassword(struct berval * attr,struct berval * pw)108bb30016cSlukem void get_userpassword(struct berval *attr,struct berval *pw)
109bb30016cSlukem {
110bb30016cSlukem 	int i;
111bb30016cSlukem 	/* go over the entries and return the remainder of the value if it
112bb30016cSlukem 		 starts with {crypt} or crypt$ */
113bb30016cSlukem 	for (i=0;!BER_BVISNULL(&attr[i]);i++)
114bb30016cSlukem 	{
115bb30016cSlukem 		if (strncasecmp(attr[i].bv_val,"{crypt}",7)==0) {
116bb30016cSlukem 			pw->bv_val = attr[i].bv_val + 7;
117bb30016cSlukem 			pw->bv_len = attr[i].bv_len - 7;
118bb30016cSlukem 			return;
119bb30016cSlukem 		}
120bb30016cSlukem 		if (strncasecmp(attr[i].bv_val,"crypt$",6)==0) {
121bb30016cSlukem 			pw->bv_val = attr[i].bv_val + 6;
122bb30016cSlukem 			pw->bv_len = attr[i].bv_len - 6;
123bb30016cSlukem 			return;
124bb30016cSlukem 		}
125bb30016cSlukem 	}
126bb30016cSlukem 	/* just return the first value completely */
127bb30016cSlukem 	*pw = *attr;
128bb30016cSlukem 	/* TODO: support more password formats e.g. SMD5
129bb30016cSlukem 		(which is $1$ but in a different format)
130bb30016cSlukem 		(any code for this is more than welcome) */
131bb30016cSlukem }
132bb30016cSlukem 
133bb30016cSlukem /* this writes a single address to the stream */
write_address(TFILE * fp,struct berval * addr)134bb30016cSlukem int write_address(TFILE *fp,struct berval *addr)
135bb30016cSlukem {
136bb30016cSlukem 	int32_t tmpint32;
137bb30016cSlukem 	struct in_addr ipv4addr;
138bb30016cSlukem 	struct in6_addr ipv6addr;
139bb30016cSlukem 	/* try to parse the address as IPv4 first, fall back to IPv6 */
140bb30016cSlukem 	if (inet_pton(AF_INET,addr->bv_val,&ipv4addr)>0)
141bb30016cSlukem 	{
142bb30016cSlukem 		/* write address type */
143bb30016cSlukem 		WRITE_INT32(fp,AF_INET);
144bb30016cSlukem 		/* write the address length */
145bb30016cSlukem 		WRITE_INT32(fp,sizeof(struct in_addr));
146bb30016cSlukem 		/* write the address itself (in network byte order) */
1478bd9f7cdSchristos 		WRITE(fp,&ipv4addr,sizeof(struct in_addr));
148bb30016cSlukem 	}
149bb30016cSlukem 	else if (inet_pton(AF_INET6,addr->bv_val,&ipv6addr)>0)
150bb30016cSlukem 	{
151bb30016cSlukem 		/* write address type */
152bb30016cSlukem 		WRITE_INT32(fp,AF_INET6);
153bb30016cSlukem 		/* write the address length */
154bb30016cSlukem 		WRITE_INT32(fp,sizeof(struct in6_addr));
155bb30016cSlukem 		/* write the address itself (in network byte order) */
1568bd9f7cdSchristos 		WRITE(fp,&ipv6addr,sizeof(struct in6_addr));
157bb30016cSlukem 	}
158bb30016cSlukem 	else
159bb30016cSlukem 	{
160bb30016cSlukem 		/* failure, log but write simple invalid address
161bb30016cSlukem 			 (otherwise the address list is messed up) */
162bb30016cSlukem 		/* TODO: have error message in correct format */
163*cf1d77f7Schristos 		Debug(LDAP_DEBUG_ANY,"nssov: unparsable address: %s\n",addr->bv_val );
164bb30016cSlukem 		/* write an illegal address type */
165bb30016cSlukem 		WRITE_INT32(fp,-1);
166bb30016cSlukem 		/* write an empty address */
167bb30016cSlukem 		WRITE_INT32(fp,0);
168bb30016cSlukem 	}
169bb30016cSlukem 	/* we're done */
170bb30016cSlukem 	return 0;
171bb30016cSlukem }
172bb30016cSlukem 
read_address(TFILE * fp,char * addr,int * addrlen,int * af)173bb30016cSlukem int read_address(TFILE *fp,char *addr,int *addrlen,int *af)
174bb30016cSlukem {
175bb30016cSlukem 	int32_t tmpint32;
176bb30016cSlukem 	int len;
177bb30016cSlukem 	/* read address family */
178bb30016cSlukem 	READ_INT32(fp,*af);
179bb30016cSlukem 	if ((*af!=AF_INET)&&(*af!=AF_INET6))
180bb30016cSlukem 	{
181*cf1d77f7Schristos 		Debug(LDAP_DEBUG_ANY,"nssov: incorrect address family specified: %d\n",*af );
182bb30016cSlukem 		return -1;
183bb30016cSlukem 	}
184bb30016cSlukem 	/* read address length */
185bb30016cSlukem 	READ_INT32(fp,len);
186bb30016cSlukem 	if ((len>*addrlen)||(len<=0))
187bb30016cSlukem 	{
188*cf1d77f7Schristos 		Debug(LDAP_DEBUG_ANY,"nssov: address length incorrect: %d\n",len );
189bb30016cSlukem 		return -1;
190bb30016cSlukem 	}
191bb30016cSlukem 	*addrlen=len;
192bb30016cSlukem 	/* read address */
193bb30016cSlukem 	READ(fp,addr,len);
194bb30016cSlukem 	/* we're done */
195bb30016cSlukem 	return 0;
196bb30016cSlukem }
197bb30016cSlukem 
nssov_escape(struct berval * src,struct berval * dst)198bb30016cSlukem int nssov_escape(struct berval *src,struct berval *dst)
199bb30016cSlukem {
200bb30016cSlukem 	size_t pos=0;
201bb30016cSlukem 	int i;
202bb30016cSlukem 	/* go over all characters in source string */
203bb30016cSlukem 	for (i=0;i<src->bv_len;i++)
204bb30016cSlukem 	{
205bb30016cSlukem 		/* check if char will fit */
206bb30016cSlukem 		if (pos>=(dst->bv_len-4))
207bb30016cSlukem 			return -1;
208bb30016cSlukem 		/* do escaping for some characters */
209bb30016cSlukem 		switch (src->bv_val[i])
210bb30016cSlukem 		{
211bb30016cSlukem 			case '*':
212bb30016cSlukem 				strcpy(dst->bv_val+pos,"\\2a");
213bb30016cSlukem 				pos+=3;
214bb30016cSlukem 				break;
215bb30016cSlukem 			case '(':
216bb30016cSlukem 				strcpy(dst->bv_val+pos,"\\28");
217bb30016cSlukem 				pos+=3;
218bb30016cSlukem 				break;
219bb30016cSlukem 			case ')':
220bb30016cSlukem 				strcpy(dst->bv_val+pos,"\\29");
221bb30016cSlukem 				pos+=3;
222bb30016cSlukem 				break;
223bb30016cSlukem 			case '\\':
224bb30016cSlukem 				strcpy(dst->bv_val+pos,"\\5c");
225bb30016cSlukem 				pos+=3;
226bb30016cSlukem 				break;
227bb30016cSlukem 			default:
228bb30016cSlukem 				/* just copy character */
229bb30016cSlukem 				dst->bv_val[pos++]=src->bv_val[i];
230bb30016cSlukem 				break;
231bb30016cSlukem 		}
232bb30016cSlukem 	}
233bb30016cSlukem 	/* terminate destination string */
234bb30016cSlukem 	dst->bv_val[pos]='\0';
235bb30016cSlukem 	dst->bv_len = pos;
236bb30016cSlukem 	return 0;
237bb30016cSlukem }
238bb30016cSlukem 
239bb30016cSlukem /* read the version information and action from the stream
240bb30016cSlukem    this function returns the read action in location pointer to by action */
read_header(TFILE * fp,int32_t * action)241bb30016cSlukem static int read_header(TFILE *fp,int32_t *action)
242bb30016cSlukem {
243bb30016cSlukem   int32_t tmpint32;
244bb30016cSlukem   /* read the protocol version */
2458bd9f7cdSchristos   READ_INT32(fp,tmpint32);
246bb30016cSlukem   if (tmpint32 != (int32_t)NSLCD_VERSION)
247bb30016cSlukem   {
248*cf1d77f7Schristos     Debug( LDAP_DEBUG_TRACE,"nssov: wrong nslcd version id (%d)\n",(int)tmpint32 );
249bb30016cSlukem     return -1;
250bb30016cSlukem   }
251bb30016cSlukem   /* read the request type */
2528bd9f7cdSchristos   READ_INT32(fp,*action);
253bb30016cSlukem   return 0;
254bb30016cSlukem }
255bb30016cSlukem 
nssov_config(nssov_info * ni,TFILE * fp,Operation * op)25633197c6aStron int nssov_config(nssov_info *ni,TFILE *fp,Operation *op)
25733197c6aStron {
25833197c6aStron 	int opt;
25933197c6aStron 	int32_t tmpint32;
26033197c6aStron 
26133197c6aStron 	READ_INT32(fp,opt);
26233197c6aStron 
263*cf1d77f7Schristos 	Debug(LDAP_DEBUG_TRACE, "nssov_config (%d)\n",opt );
26433197c6aStron 
2658bd9f7cdSchristos 	WRITE_INT32(fp,NSLCD_VERSION);
2668bd9f7cdSchristos 	WRITE_INT32(fp,NSLCD_ACTION_CONFIG_GET);
2678bd9f7cdSchristos 	WRITE_INT32(fp,NSLCD_RESULT_BEGIN);
2688bd9f7cdSchristos 
26933197c6aStron 	switch (opt) {
27033197c6aStron 	case NSLCD_CONFIG_PAM_PASSWORD_PROHIBIT_MESSAGE:
2718bd9f7cdSchristos 		/* request for pam password_prohibit_message */
27233197c6aStron 		/* nssov_pam prohibits password  */
27333197c6aStron 		if (!BER_BVISEMPTY(&ni->ni_pam_password_prohibit_message)) {
27433197c6aStron 			Debug(LDAP_DEBUG_TRACE,"nssov_config(): %s (%s)\n",
27533197c6aStron 				"password_prohibit_message",
276*cf1d77f7Schristos 				ni->ni_pam_password_prohibit_message.bv_val );
2778bd9f7cdSchristos 			WRITE_STRING(fp,ni->ni_pam_password_prohibit_message.bv_val);
27833197c6aStron 		}
27933197c6aStron 	default:
2808bd9f7cdSchristos 		/* all other config options are ignored */
28133197c6aStron 		break;
28233197c6aStron 	}
28333197c6aStron 
28433197c6aStron 	WRITE_INT32(fp,NSLCD_RESULT_END);
28533197c6aStron 	return 0;
28633197c6aStron }
28733197c6aStron 
28833197c6aStron 
289bb30016cSlukem /* read a request message, returns <0 in case of errors,
290bb30016cSlukem    this function closes the socket */
handleconnection(nssov_info * ni,int sock,Operation * op)291bb30016cSlukem static void handleconnection(nssov_info *ni,int sock,Operation *op)
292bb30016cSlukem {
293bb30016cSlukem   TFILE *fp;
294bb30016cSlukem   int32_t action;
29533197c6aStron   int readtimeout,writetimeout;
296bb30016cSlukem   uid_t uid;
297bb30016cSlukem   gid_t gid;
298bb30016cSlukem   char authid[sizeof("gidNumber=4294967295+uidNumber=424967295,cn=peercred,cn=external,cn=auth")];
29933197c6aStron   char peerbuf[8];
30033197c6aStron   struct berval peerbv = { sizeof(peerbuf), peerbuf };
301bb30016cSlukem 
302bb30016cSlukem   /* log connection */
303*cf1d77f7Schristos   if (LUTIL_GETPEEREID(sock,&uid,&gid,&peerbv)) {
304*cf1d77f7Schristos     char ebuf[128];
305*cf1d77f7Schristos     int saved_errno = errno;
306*cf1d77f7Schristos     Debug( LDAP_DEBUG_TRACE,"nssov: connection from unknown client: %s\n",
307*cf1d77f7Schristos                       AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
308*cf1d77f7Schristos   } else {
3094e6df137Slukem     Debug( LDAP_DEBUG_TRACE,"nssov: connection from uid=%d gid=%d\n",
310*cf1d77f7Schristos                       (int)uid,(int)gid );
311*cf1d77f7Schristos   }
312bb30016cSlukem 
313bb30016cSlukem   /* Should do authid mapping too */
314bb30016cSlukem   op->o_dn.bv_len = sprintf(authid,"gidNumber=%d+uidNumber=%d,cn=peercred,cn=external,cn=auth",
31533197c6aStron 	(int)gid, (int)uid );
316bb30016cSlukem   op->o_dn.bv_val = authid;
317bb30016cSlukem   op->o_ndn = op->o_dn;
318bb30016cSlukem 
31933197c6aStron   /* set the timeouts:
32033197c6aStron    * read timeout is half a second because clients should send their request
32133197c6aStron    * quickly, write timeout is 60 seconds because clients could be taking some
32233197c6aStron    * time to process the results
32333197c6aStron    */
32433197c6aStron   readtimeout = 500;
32533197c6aStron   writetimeout = 60000;
326bb30016cSlukem   /* create a stream object */
32733197c6aStron   if ((fp=tio_fdopen(sock,readtimeout,writetimeout,
328bb30016cSlukem                      READBUFFER_MINSIZE,READBUFFER_MAXSIZE,
329bb30016cSlukem                      WRITEBUFFER_MINSIZE,WRITEBUFFER_MAXSIZE))==NULL)
330bb30016cSlukem   {
331*cf1d77f7Schristos     char ebuf[128];
332*cf1d77f7Schristos     int saved_errno = errno;
333*cf1d77f7Schristos     Debug( LDAP_DEBUG_ANY,"nssov: cannot create stream for writing: %s",
334*cf1d77f7Schristos                       AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
335bb30016cSlukem     (void)close(sock);
336bb30016cSlukem     return;
337bb30016cSlukem   }
338bb30016cSlukem   /* read request */
339bb30016cSlukem   if (read_header(fp,&action))
340bb30016cSlukem   {
341bb30016cSlukem     (void)tio_close(fp);
342bb30016cSlukem     return;
343bb30016cSlukem   }
344bb30016cSlukem   /* handle request */
345bb30016cSlukem   switch (action)
346bb30016cSlukem   {
347bb30016cSlukem     case NSLCD_ACTION_ALIAS_BYNAME:     (void)nssov_alias_byname(ni,fp,op); break;
348bb30016cSlukem     case NSLCD_ACTION_ALIAS_ALL:        (void)nssov_alias_all(ni,fp,op); break;
349bb30016cSlukem     case NSLCD_ACTION_ETHER_BYNAME:     (void)nssov_ether_byname(ni,fp,op); break;
350bb30016cSlukem     case NSLCD_ACTION_ETHER_BYETHER:    (void)nssov_ether_byether(ni,fp,op); break;
351bb30016cSlukem     case NSLCD_ACTION_ETHER_ALL:        (void)nssov_ether_all(ni,fp,op); break;
352bb30016cSlukem     case NSLCD_ACTION_GROUP_BYNAME:     (void)nssov_group_byname(ni,fp,op); break;
353bb30016cSlukem     case NSLCD_ACTION_GROUP_BYGID:      (void)nssov_group_bygid(ni,fp,op); break;
354bb30016cSlukem     case NSLCD_ACTION_GROUP_BYMEMBER:   (void)nssov_group_bymember(ni,fp,op); break;
355bb30016cSlukem     case NSLCD_ACTION_GROUP_ALL:        (void)nssov_group_all(ni,fp,op); break;
356bb30016cSlukem     case NSLCD_ACTION_HOST_BYNAME:      (void)nssov_host_byname(ni,fp,op); break;
357bb30016cSlukem     case NSLCD_ACTION_HOST_BYADDR:      (void)nssov_host_byaddr(ni,fp,op); break;
358bb30016cSlukem     case NSLCD_ACTION_HOST_ALL:         (void)nssov_host_all(ni,fp,op); break;
359bb30016cSlukem     case NSLCD_ACTION_NETGROUP_BYNAME:  (void)nssov_netgroup_byname(ni,fp,op); break;
360bb30016cSlukem     case NSLCD_ACTION_NETWORK_BYNAME:   (void)nssov_network_byname(ni,fp,op); break;
361bb30016cSlukem     case NSLCD_ACTION_NETWORK_BYADDR:   (void)nssov_network_byaddr(ni,fp,op); break;
362bb30016cSlukem     case NSLCD_ACTION_NETWORK_ALL:      (void)nssov_network_all(ni,fp,op); break;
363bb30016cSlukem     case NSLCD_ACTION_PASSWD_BYNAME:    (void)nssov_passwd_byname(ni,fp,op); break;
364bb30016cSlukem     case NSLCD_ACTION_PASSWD_BYUID:     (void)nssov_passwd_byuid(ni,fp,op); break;
365bb30016cSlukem     case NSLCD_ACTION_PASSWD_ALL:       (void)nssov_passwd_all(ni,fp,op); break;
366bb30016cSlukem     case NSLCD_ACTION_PROTOCOL_BYNAME:  (void)nssov_protocol_byname(ni,fp,op); break;
367bb30016cSlukem     case NSLCD_ACTION_PROTOCOL_BYNUMBER:(void)nssov_protocol_bynumber(ni,fp,op); break;
368bb30016cSlukem     case NSLCD_ACTION_PROTOCOL_ALL:     (void)nssov_protocol_all(ni,fp,op); break;
369bb30016cSlukem     case NSLCD_ACTION_RPC_BYNAME:       (void)nssov_rpc_byname(ni,fp,op); break;
370bb30016cSlukem     case NSLCD_ACTION_RPC_BYNUMBER:     (void)nssov_rpc_bynumber(ni,fp,op); break;
371bb30016cSlukem     case NSLCD_ACTION_RPC_ALL:          (void)nssov_rpc_all(ni,fp,op); break;
372bb30016cSlukem     case NSLCD_ACTION_SERVICE_BYNAME:   (void)nssov_service_byname(ni,fp,op); break;
373bb30016cSlukem     case NSLCD_ACTION_SERVICE_BYNUMBER: (void)nssov_service_bynumber(ni,fp,op); break;
374bb30016cSlukem     case NSLCD_ACTION_SERVICE_ALL:      (void)nssov_service_all(ni,fp,op); break;
375bb30016cSlukem     case NSLCD_ACTION_SHADOW_BYNAME:    if (uid==0) (void)nssov_shadow_byname(ni,fp,op); break;
376bb30016cSlukem     case NSLCD_ACTION_SHADOW_ALL:       if (uid==0) (void)nssov_shadow_all(ni,fp,op); break;
3778bd9f7cdSchristos 	case NSLCD_ACTION_PAM_AUTHC:		(void)pam_authc(ni,fp,op,uid); break;
3784e6df137Slukem 	case NSLCD_ACTION_PAM_AUTHZ:		(void)pam_authz(ni,fp,op); break;
3794e6df137Slukem 	case NSLCD_ACTION_PAM_SESS_O:		if (uid==0) (void)pam_sess_o(ni,fp,op); break;
3804e6df137Slukem 	case NSLCD_ACTION_PAM_SESS_C:		if (uid==0) (void)pam_sess_c(ni,fp,op); break;
3818bd9f7cdSchristos 	case NSLCD_ACTION_PAM_PWMOD:		(void)pam_pwmod(ni,fp,op,uid); break;
38233197c6aStron 	case NSLCD_ACTION_CONFIG_GET:			(void)nssov_config(ni,fp,op); break;
383bb30016cSlukem     default:
384*cf1d77f7Schristos       Debug( LDAP_DEBUG_ANY,"nssov: invalid request id: %d",(int)action );
385bb30016cSlukem       break;
386bb30016cSlukem   }
387bb30016cSlukem   /* we're done with the request */
388bb30016cSlukem   (void)tio_close(fp);
389bb30016cSlukem   return;
390bb30016cSlukem }
391bb30016cSlukem 
392bb30016cSlukem /* accept a connection on the socket */
acceptconn(void * ctx,void * arg)393bb30016cSlukem static void *acceptconn(void *ctx, void *arg)
394bb30016cSlukem {
395bb30016cSlukem 	nssov_info *ni = arg;
396bb30016cSlukem 	Connection conn = {0};
397bb30016cSlukem 	OperationBuffer opbuf;
398bb30016cSlukem 	Operation *op;
399bb30016cSlukem 	int csock;
400bb30016cSlukem 
401bb30016cSlukem 	if ( slapd_shutdown )
402bb30016cSlukem 		return NULL;
403bb30016cSlukem 
404bb30016cSlukem 	{
405bb30016cSlukem 		struct sockaddr_storage addr;
406bb30016cSlukem 		socklen_t alen;
407bb30016cSlukem 		int j;
408bb30016cSlukem 
409bb30016cSlukem 		/* accept a new connection */
410bb30016cSlukem 		alen=(socklen_t)sizeof(struct sockaddr_storage);
411bb30016cSlukem 		csock=accept(ni->ni_socket,(struct sockaddr *)&addr,&alen);
412bb30016cSlukem 		connection_client_enable(ni->ni_conn);
413bb30016cSlukem 		if (csock<0)
414bb30016cSlukem 		{
415*cf1d77f7Schristos 			char ebuf[128];
416*cf1d77f7Schristos 			int saved_errno = errno;
417bb30016cSlukem 			if ((errno==EINTR)||(errno==EAGAIN)||(errno==EWOULDBLOCK))
418bb30016cSlukem 			{
419*cf1d77f7Schristos 				Debug( LDAP_DEBUG_TRACE,"nssov: accept() failed (ignored): %s",
420*cf1d77f7Schristos 					AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
4218bd9f7cdSchristos 				return NULL;
422bb30016cSlukem 			}
423*cf1d77f7Schristos 			Debug( LDAP_DEBUG_ANY,"nssov: accept() failed: %s",
424*cf1d77f7Schristos 				AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
4258bd9f7cdSchristos 			return NULL;
426bb30016cSlukem 		}
427bb30016cSlukem 		/* make sure O_NONBLOCK is not inherited */
428bb30016cSlukem 		if ((j=fcntl(csock,F_GETFL,0))<0)
429bb30016cSlukem 		{
430*cf1d77f7Schristos 			char ebuf[128];
431*cf1d77f7Schristos 			int saved_errno = errno;
432*cf1d77f7Schristos 			Debug( LDAP_DEBUG_ANY,"nssov: fcntl(F_GETFL) failed: %s",
433*cf1d77f7Schristos 				AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
434*cf1d77f7Schristos 			if (close(csock)) {
435*cf1d77f7Schristos 				saved_errno = errno;
436*cf1d77f7Schristos 				Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",
437*cf1d77f7Schristos 					AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
438*cf1d77f7Schristos 			}
4398bd9f7cdSchristos 			return NULL;
440bb30016cSlukem 		}
441bb30016cSlukem 		if (fcntl(csock,F_SETFL,j&~O_NONBLOCK)<0)
442bb30016cSlukem 		{
443*cf1d77f7Schristos 			char ebuf[128];
444*cf1d77f7Schristos 			int saved_errno = errno;
445*cf1d77f7Schristos 			Debug( LDAP_DEBUG_ANY,"nssov: fcntl(F_SETFL,~O_NONBLOCK) failed: %s",
446*cf1d77f7Schristos 				AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
447*cf1d77f7Schristos 			if (close(csock)) {
448*cf1d77f7Schristos 				saved_errno = errno;
449*cf1d77f7Schristos 				Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",
450*cf1d77f7Schristos 					AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
451*cf1d77f7Schristos 			}
4528bd9f7cdSchristos 			return NULL;
453bb30016cSlukem 		}
454bb30016cSlukem 	}
455bb30016cSlukem 	connection_fake_init( &conn, &opbuf, ctx );
456bb30016cSlukem 	op=&opbuf.ob_op;
4574e6df137Slukem 	conn.c_ssf = conn.c_transport_ssf = local_ssf;
458bb30016cSlukem 	op->o_bd = ni->ni_db;
459bb30016cSlukem 	op->o_tag = LDAP_REQ_SEARCH;
460bb30016cSlukem 
461bb30016cSlukem 	/* handle the connection */
462bb30016cSlukem 	handleconnection(ni,csock,op);
4638bd9f7cdSchristos 
4648bd9f7cdSchristos 	return NULL;
465bb30016cSlukem }
466bb30016cSlukem 
467bb30016cSlukem static slap_verbmasks nss_svcs[] = {
4684e6df137Slukem 	{ BER_BVC("aliases"), NM_alias },
4694e6df137Slukem 	{ BER_BVC("ethers"), NM_ether },
470bb30016cSlukem 	{ BER_BVC("group"), NM_group },
4714e6df137Slukem 	{ BER_BVC("hosts"), NM_host },
472bb30016cSlukem 	{ BER_BVC("netgroup"), NM_netgroup },
4734e6df137Slukem 	{ BER_BVC("networks"), NM_network },
474bb30016cSlukem 	{ BER_BVC("passwd"), NM_passwd },
4754e6df137Slukem 	{ BER_BVC("protocols"), NM_protocol },
476bb30016cSlukem 	{ BER_BVC("rpc"), NM_rpc },
4774e6df137Slukem 	{ BER_BVC("services"), NM_service },
478bb30016cSlukem 	{ BER_BVC("shadow"), NM_shadow },
479bb30016cSlukem 	{ BER_BVNULL, 0 }
480bb30016cSlukem };
481bb30016cSlukem 
4824e6df137Slukem static slap_verbmasks pam_opts[] = {
4834e6df137Slukem 	{ BER_BVC("userhost"), NI_PAM_USERHOST },
4844e6df137Slukem 	{ BER_BVC("userservice"), NI_PAM_USERSVC },
4854e6df137Slukem 	{ BER_BVC("usergroup"), NI_PAM_USERGRP },
4864e6df137Slukem 	{ BER_BVC("hostservice"), NI_PAM_HOSTSVC },
4874e6df137Slukem 	{ BER_BVC("authz2dn"), NI_PAM_SASL2DN },
4884e6df137Slukem 	{ BER_BVC("uid2dn"), NI_PAM_UID2DN },
4894e6df137Slukem 	{ BER_BVNULL, 0 }
4904e6df137Slukem };
4914e6df137Slukem 
492bb30016cSlukem enum {
493bb30016cSlukem 	NSS_SSD=1,
4944e6df137Slukem 	NSS_MAP,
4954e6df137Slukem 	NSS_PAM,
4964e6df137Slukem 	NSS_PAMGROUP,
4974e6df137Slukem 	NSS_PAMSESS
498bb30016cSlukem };
499bb30016cSlukem 
500bb30016cSlukem static ConfigDriver nss_cf_gen;
501bb30016cSlukem 
502bb30016cSlukem static ConfigTable nsscfg[] = {
503bb30016cSlukem 	{ "nssov-ssd", "service> <url", 3, 3, 0, ARG_MAGIC|NSS_SSD,
504bb30016cSlukem 		nss_cf_gen, "(OLcfgCtAt:3.1 NAME 'olcNssSsd' "
505bb30016cSlukem 			"DESC 'URL for searches in a given service' "
506bb30016cSlukem 			"EQUALITY caseIgnoreMatch "
507bb30016cSlukem 			"SYNTAX OMsDirectoryString )", NULL, NULL },
508bb30016cSlukem 	{ "nssov-map", "service> <orig> <new", 4, 4, 0, ARG_MAGIC|NSS_MAP,
509bb30016cSlukem 		nss_cf_gen, "(OLcfgCtAt:3.2 NAME 'olcNssMap' "
510bb30016cSlukem 			"DESC 'Map <service> lookups of <orig> attr to <new> attr' "
511bb30016cSlukem 			"EQUALITY caseIgnoreMatch "
512bb30016cSlukem 			"SYNTAX OMsDirectoryString )", NULL, NULL },
5134e6df137Slukem 	{ "nssov-pam", "options", 2, 0, 0, ARG_MAGIC|NSS_PAM,
5144e6df137Slukem 		nss_cf_gen, "(OLcfgCtAt:3.3 NAME 'olcNssPam' "
5154e6df137Slukem 			"DESC 'PAM authentication and authorization options' "
5164e6df137Slukem 			"EQUALITY caseIgnoreMatch "
5174e6df137Slukem 			"SYNTAX OMsDirectoryString )", NULL, NULL },
5184e6df137Slukem 	{ "nssov-pam-defhost", "hostname", 2, 2, 0, ARG_OFFSET|ARG_BERVAL,
5194e6df137Slukem 		(void *)offsetof(struct nssov_info, ni_pam_defhost),
5204e6df137Slukem 		"(OLcfgCtAt:3.4 NAME 'olcNssPamDefHost' "
5214e6df137Slukem 			"DESC 'Default hostname for service checks' "
5224e6df137Slukem 			"EQUALITY caseIgnoreMatch "
5234e6df137Slukem 			"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
5244e6df137Slukem 	{ "nssov-pam-group-dn", "DN", 2, 2, 0, ARG_MAGIC|ARG_DN|NSS_PAMGROUP,
5254e6df137Slukem 		nss_cf_gen, "(OLcfgCtAt:3.5 NAME 'olcNssPamGroupDN' "
5264e6df137Slukem 			"DESC 'DN of group in which membership is required' "
5274e6df137Slukem 			"EQUALITY distinguishedNameMatch "
5284e6df137Slukem 			"SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
5294e6df137Slukem 	{ "nssov-pam-group-ad", "attr", 2, 2, 0, ARG_OFFSET|ARG_ATDESC,
5304e6df137Slukem 		(void *)offsetof(struct nssov_info, ni_pam_group_ad),
5314e6df137Slukem 		"(OLcfgCtAt:3.6 NAME 'olcNssPamGroupAD' "
5324e6df137Slukem 			"DESC 'Member attribute to use for group check' "
5334e6df137Slukem 			"EQUALITY caseIgnoreMatch "
5344e6df137Slukem 			"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
5354e6df137Slukem 	{ "nssov-pam-min-uid", "uid", 2, 2, 0, ARG_OFFSET|ARG_INT,
5364e6df137Slukem 		(void *)offsetof(struct nssov_info, ni_pam_min_uid),
5374e6df137Slukem 		"(OLcfgCtAt:3.7 NAME 'olcNssPamMinUid' "
5384e6df137Slukem 			"DESC 'Minimum UID allowed to login' "
5394e6df137Slukem 			"EQUALITY integerMatch "
5404e6df137Slukem 			"SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
5414e6df137Slukem 	{ "nssov-pam-max-uid", "uid", 2, 2, 0, ARG_OFFSET|ARG_INT,
5424e6df137Slukem 		(void *)offsetof(struct nssov_info, ni_pam_max_uid),
5434e6df137Slukem 		"(OLcfgCtAt:3.8 NAME 'olcNssPamMaxUid' "
5444e6df137Slukem 			"DESC 'Maximum UID allowed to login' "
5454e6df137Slukem 			"EQUALITY integerMatch "
5464e6df137Slukem 			"SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
5474e6df137Slukem 	{ "nssov-pam-template-ad", "attr", 2, 2, 0, ARG_OFFSET|ARG_ATDESC,
5484e6df137Slukem 		(void *)offsetof(struct nssov_info, ni_pam_template_ad),
5494e6df137Slukem 		"(OLcfgCtAt:3.9 NAME 'olcNssPamTemplateAD' "
5504e6df137Slukem 			"DESC 'Attribute to use for template login name' "
5514e6df137Slukem 			"EQUALITY caseIgnoreMatch "
5524e6df137Slukem 			"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
5534e6df137Slukem 	{ "nssov-pam-template", "name", 2, 2, 0, ARG_OFFSET|ARG_BERVAL,
5544e6df137Slukem 		(void *)offsetof(struct nssov_info, ni_pam_template),
5554e6df137Slukem 		"(OLcfgCtAt:3.10 NAME 'olcNssPamTemplate' "
5564e6df137Slukem 			"DESC 'Default template login name' "
5574e6df137Slukem 			"EQUALITY caseIgnoreMatch "
5584e6df137Slukem 			"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
55933197c6aStron 	{ "nssov-pam-session", "service", 2, 2, 0, ARG_MAGIC|NSS_PAMSESS,
5604e6df137Slukem 		nss_cf_gen, "(OLcfgCtAt:3.11 NAME 'olcNssPamSession' "
5614e6df137Slukem 			"DESC 'Services for which sessions will be recorded' "
5624e6df137Slukem 			"EQUALITY caseIgnoreMatch "
5634e6df137Slukem 			"SYNTAX OMsDirectoryString )", NULL, NULL },
56433197c6aStron 	{ "nssov-pam-password-prohibit-message",
56533197c6aStron 		"password_prohibit_message", 2, 2, 0,
56633197c6aStron 		ARG_OFFSET|ARG_BERVAL,
56733197c6aStron 		(void *)offsetof(struct nssov_info, ni_pam_password_prohibit_message),
56833197c6aStron 		"(OLcfgCtAt:3.12 NAME 'olcNssPamPwdProhibitMsg' "
56933197c6aStron 			"DESC 'Prohibit password modification message' "
57033197c6aStron 			"EQUALITY caseIgnoreMatch "
57133197c6aStron 			"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
57233197c6aStron 	{ "nssov-pam-pwdmgr-dn",
57333197c6aStron 		"pwdmgr_dn", 2, 2, 0,
57433197c6aStron 		ARG_OFFSET|ARG_BERVAL,
57533197c6aStron 		(void *)offsetof(struct nssov_info, ni_pam_pwdmgr_dn),
57633197c6aStron 		"(OLcfgCtAt:3.13 NAME 'olcPamPwdmgrDn' "
57733197c6aStron 			"DESC 'Password Manager DN' "
57833197c6aStron 			"EQUALITY distinguishedNameMatch "
57933197c6aStron 			"SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
58033197c6aStron 	{ "nssov-pam-pwdmgr-pwd",
58133197c6aStron 		"pwdmgr_pwd", 2, 2, 0,
58233197c6aStron 		ARG_OFFSET|ARG_BERVAL,
58333197c6aStron 		(void *)offsetof(struct nssov_info, ni_pam_pwdmgr_pwd),
58433197c6aStron 		"(OLcfgCtAt:3.14 NAME 'olcPamPwdmgrPwd' "
58533197c6aStron 			"DESC 'Password Manager Pwd' "
58633197c6aStron 			"EQUALITY octetStringMatch "
58733197c6aStron 			"SYNTAX OMsOctetString SINGLE-VALUE )", NULL, NULL },
588bb30016cSlukem 	{ NULL, NULL, 0,0,0, ARG_IGNORED }
589bb30016cSlukem };
590bb30016cSlukem 
591bb30016cSlukem static ConfigOCs nssocs[] = {
592bb30016cSlukem 	{ "( OLcfgCtOc:3.1 "
593bb30016cSlukem 		"NAME 'olcNssOvConfig' "
594bb30016cSlukem 		"DESC 'NSS lookup configuration' "
595bb30016cSlukem 		"SUP olcOverlayConfig "
5964e6df137Slukem 		"MAY ( olcNssSsd $ olcNssMap $ olcNssPam $ olcNssPamDefHost $ "
5974e6df137Slukem 			"olcNssPamGroupDN $ olcNssPamGroupAD $ "
5984e6df137Slukem 			"olcNssPamMinUid $ olcNssPamMaxUid $ olcNssPamSession $ "
5994e6df137Slukem 			"olcNssPamTemplateAD $ olcNssPamTemplate ) )",
600bb30016cSlukem 		Cft_Overlay, nsscfg },
601bb30016cSlukem 	{ NULL, 0, NULL }
602bb30016cSlukem };
603bb30016cSlukem 
604bb30016cSlukem static int
nss_cf_gen(ConfigArgs * c)605bb30016cSlukem nss_cf_gen(ConfigArgs *c)
606bb30016cSlukem {
607bb30016cSlukem 	slap_overinst *on = (slap_overinst *)c->bi;
608bb30016cSlukem 	nssov_info *ni = on->on_bi.bi_private;
609bb30016cSlukem 	nssov_mapinfo *mi;
610bb30016cSlukem 	int i, j, rc = 0;
6114e6df137Slukem 	slap_mask_t m;
612bb30016cSlukem 
613bb30016cSlukem 	if ( c->op == SLAP_CONFIG_EMIT ) {
614bb30016cSlukem 		switch(c->type) {
615bb30016cSlukem 		case NSS_SSD:
616bb30016cSlukem 			rc = 1;
617bb30016cSlukem 			for (i=NM_alias;i<NM_NONE;i++) {
618bb30016cSlukem 				struct berval scope;
619bb30016cSlukem 				struct berval ssd;
620bb30016cSlukem 				struct berval base;
621bb30016cSlukem 
622bb30016cSlukem 				mi = &ni->ni_maps[i];
623bb30016cSlukem 
624bb30016cSlukem 				/* ignore all-default services */
625bb30016cSlukem 				if ( mi->mi_scope == LDAP_SCOPE_DEFAULT &&
626bb30016cSlukem 					bvmatch( &mi->mi_filter, &mi->mi_filter0 ) &&
627bb30016cSlukem 					BER_BVISNULL( &mi->mi_base ))
628bb30016cSlukem 					continue;
629bb30016cSlukem 
630bb30016cSlukem 				if ( BER_BVISNULL( &mi->mi_base ))
631bb30016cSlukem 					base = ni->ni_db->be_nsuffix[0];
632bb30016cSlukem 				else
633bb30016cSlukem 					base = mi->mi_base;
634bb30016cSlukem 				ldap_pvt_scope2bv(mi->mi_scope == LDAP_SCOPE_DEFAULT ?
635bb30016cSlukem 					LDAP_SCOPE_SUBTREE : mi->mi_scope, &scope);
636bb30016cSlukem 				ssd.bv_len = STRLENOF(" ldap:///???") + nss_svcs[i].word.bv_len +
637bb30016cSlukem 					base.bv_len + scope.bv_len + mi->mi_filter.bv_len;
638bb30016cSlukem 				ssd.bv_val = ch_malloc( ssd.bv_len + 1 );
639bb30016cSlukem 				sprintf(ssd.bv_val, "%s ldap:///%s??%s?%s", nss_svcs[i].word.bv_val,
640bb30016cSlukem 					base.bv_val, scope.bv_val, mi->mi_filter.bv_val );
641bb30016cSlukem 				ber_bvarray_add( &c->rvalue_vals, &ssd );
642bb30016cSlukem 				rc = 0;
643bb30016cSlukem 			}
644bb30016cSlukem 			break;
645bb30016cSlukem 		case NSS_MAP:
646bb30016cSlukem 			rc = 1;
647bb30016cSlukem 			for (i=NM_alias;i<NM_NONE;i++) {
648bb30016cSlukem 
649bb30016cSlukem 				mi = &ni->ni_maps[i];
650bb30016cSlukem 				for (j=0;!BER_BVISNULL(&mi->mi_attrkeys[j]);j++) {
651bb30016cSlukem 					if ( ber_bvstrcasecmp(&mi->mi_attrkeys[j],
652bb30016cSlukem 						&mi->mi_attrs[j].an_name)) {
653bb30016cSlukem 						struct berval map;
654bb30016cSlukem 
655bb30016cSlukem 						map.bv_len = nss_svcs[i].word.bv_len +
656bb30016cSlukem 							mi->mi_attrkeys[j].bv_len +
6574e6df137Slukem 							mi->mi_attrs[j].an_desc->ad_cname.bv_len + 2;
658bb30016cSlukem 						map.bv_val = ch_malloc(map.bv_len + 1);
659bb30016cSlukem 						sprintf(map.bv_val, "%s %s %s", nss_svcs[i].word.bv_val,
6604e6df137Slukem 							mi->mi_attrkeys[j].bv_val, mi->mi_attrs[j].an_desc->ad_cname.bv_val );
661bb30016cSlukem 						ber_bvarray_add( &c->rvalue_vals, &map );
662bb30016cSlukem 						rc = 0;
663bb30016cSlukem 					}
664bb30016cSlukem 				}
665bb30016cSlukem 			}
666bb30016cSlukem 			break;
6674e6df137Slukem 		case NSS_PAM:
6684e6df137Slukem 			rc = mask_to_verbs( pam_opts, ni->ni_pam_opts, &c->rvalue_vals );
6694e6df137Slukem 			break;
6704e6df137Slukem 		case NSS_PAMGROUP:
6714e6df137Slukem 			if (!BER_BVISEMPTY( &ni->ni_pam_group_dn )) {
6724e6df137Slukem 				value_add_one( &c->rvalue_vals, &ni->ni_pam_group_dn );
6734e6df137Slukem 				value_add_one( &c->rvalue_nvals, &ni->ni_pam_group_dn );
6744e6df137Slukem 			} else {
6754e6df137Slukem 				rc = 1;
6764e6df137Slukem 			}
6774e6df137Slukem 			break;
6784e6df137Slukem 		case NSS_PAMSESS:
6794e6df137Slukem 			if (ni->ni_pam_sessions) {
6804e6df137Slukem 				ber_bvarray_dup_x( &c->rvalue_vals, ni->ni_pam_sessions, NULL );
6814e6df137Slukem 			} else {
6824e6df137Slukem 				rc = 1;
6834e6df137Slukem 			}
6844e6df137Slukem 			break;
685bb30016cSlukem 		}
686bb30016cSlukem 		return rc;
687bb30016cSlukem 	} else if ( c->op == LDAP_MOD_DELETE ) {
6884e6df137Slukem 		/* FIXME */
689bb30016cSlukem 		return 1;
690bb30016cSlukem 	}
691bb30016cSlukem 	switch( c->type ) {
692bb30016cSlukem 	case NSS_SSD: {
693bb30016cSlukem 		LDAPURLDesc *lud;
694bb30016cSlukem 
695bb30016cSlukem 		i = verb_to_mask(c->argv[1], nss_svcs);
696bb30016cSlukem 		if ( i == NM_NONE )
697bb30016cSlukem 			return 1;
698bb30016cSlukem 
699bb30016cSlukem 		mi = &ni->ni_maps[i];
700bb30016cSlukem 		rc = ldap_url_parse(c->argv[2], &lud);
701bb30016cSlukem 		if ( rc )
702bb30016cSlukem 			return 1;
703bb30016cSlukem 		do {
704bb30016cSlukem 			struct berval base;
705bb30016cSlukem 			/* Must be LDAP scheme */
706bb30016cSlukem 			if (strcasecmp(lud->lud_scheme,"ldap")) {
707bb30016cSlukem 				rc = 1;
708bb30016cSlukem 				break;
709bb30016cSlukem 			}
710bb30016cSlukem 			/* Host part, attrs, and extensions must be empty */
711bb30016cSlukem 			if (( lud->lud_host && *lud->lud_host ) ||
712bb30016cSlukem 				lud->lud_attrs || lud->lud_exts ) {
713bb30016cSlukem 				rc = 1;
714bb30016cSlukem 				break;
715bb30016cSlukem 			}
716bb30016cSlukem 			ber_str2bv( lud->lud_dn,0,0,&base);
717bb30016cSlukem 			rc = dnNormalize( 0,NULL,NULL,&base,&mi->mi_base,NULL);
718bb30016cSlukem 			if ( rc )
719bb30016cSlukem 				break;
720bb30016cSlukem 			if ( lud->lud_filter ) {
721bb30016cSlukem 				/* steal this */
722bb30016cSlukem 				ber_str2bv( lud->lud_filter,0,0,&mi->mi_filter);
723bb30016cSlukem 				lud->lud_filter = NULL;
724bb30016cSlukem 			}
725bb30016cSlukem 			mi->mi_scope = lud->lud_scope;
726bb30016cSlukem 		} while(0);
727bb30016cSlukem 		ldap_free_urldesc( lud );
728bb30016cSlukem 		}
729bb30016cSlukem 		break;
730bb30016cSlukem 	case NSS_MAP:
731bb30016cSlukem 		i = verb_to_mask(c->argv[1], nss_svcs);
732bb30016cSlukem 		if ( i == NM_NONE )
733bb30016cSlukem 			return 1;
734bb30016cSlukem 		rc = 1;
735bb30016cSlukem 		mi = &ni->ni_maps[i];
736bb30016cSlukem 		for (j=0; !BER_BVISNULL(&mi->mi_attrkeys[j]); j++) {
737bb30016cSlukem 			if (!strcasecmp(c->argv[2],mi->mi_attrkeys[j].bv_val)) {
738bb30016cSlukem 				AttributeDescription *ad = NULL;
739bb30016cSlukem 				const char *text;
740bb30016cSlukem 				rc = slap_str2ad( c->argv[3], &ad, &text);
741bb30016cSlukem 				if ( rc == 0 ) {
742bb30016cSlukem 					mi->mi_attrs[j].an_desc = ad;
743bb30016cSlukem 					mi->mi_attrs[j].an_name = ad->ad_cname;
744bb30016cSlukem 				}
745bb30016cSlukem 				break;
746bb30016cSlukem 			}
747bb30016cSlukem 		}
748bb30016cSlukem 		break;
7494e6df137Slukem 	case NSS_PAM:
7504e6df137Slukem 		m = ni->ni_pam_opts;
7514e6df137Slukem 		i = verbs_to_mask(c->argc, c->argv, pam_opts, &m);
7524e6df137Slukem 		if (i == 0) {
7534e6df137Slukem 			ni->ni_pam_opts = m;
7544e6df137Slukem 			if ((m & NI_PAM_USERHOST) && !nssov_pam_host_ad) {
7554e6df137Slukem 				const char *text;
7564e6df137Slukem 				i = slap_str2ad("host", &nssov_pam_host_ad, &text);
7574e6df137Slukem 				if (i != LDAP_SUCCESS) {
7584e6df137Slukem 					snprintf(c->cr_msg, sizeof(c->cr_msg),
7594e6df137Slukem 						"nssov: host attr unknown: %s", text);
760*cf1d77f7Schristos 					Debug(LDAP_DEBUG_ANY,"%s\n",c->cr_msg );
7614e6df137Slukem 					rc = 1;
7624e6df137Slukem 					break;
7634e6df137Slukem 				}
7644e6df137Slukem 			}
7654e6df137Slukem 			if ((m & (NI_PAM_USERSVC|NI_PAM_HOSTSVC)) && !nssov_pam_svc_ad) {
7664e6df137Slukem 				const char *text;
7674e6df137Slukem 				i = slap_str2ad("authorizedService", &nssov_pam_svc_ad, &text);
7684e6df137Slukem 				if (i != LDAP_SUCCESS) {
7694e6df137Slukem 					snprintf(c->cr_msg, sizeof(c->cr_msg),
7704e6df137Slukem 						"nssov: authorizedService attr unknown: %s", text);
771*cf1d77f7Schristos 					Debug(LDAP_DEBUG_ANY,"%s\n",c->cr_msg );
7724e6df137Slukem 					rc = 1;
7734e6df137Slukem 					break;
7744e6df137Slukem 				}
7754e6df137Slukem 			}
7764e6df137Slukem 		} else {
7774e6df137Slukem 			rc = 1;
7784e6df137Slukem 		}
7794e6df137Slukem 		break;
7804e6df137Slukem 	case NSS_PAMGROUP:
7814e6df137Slukem 		ni->ni_pam_group_dn = c->value_ndn;
7824e6df137Slukem 		ch_free( c->value_dn.bv_val );
7834e6df137Slukem 		break;
7844e6df137Slukem 	case NSS_PAMSESS:
78533197c6aStron 		ber_str2bv( c->argv[1], 0, 1, &c->value_bv );
7864e6df137Slukem 		ber_bvarray_add( &ni->ni_pam_sessions, &c->value_bv );
7874e6df137Slukem 		break;
788bb30016cSlukem 	}
789bb30016cSlukem 	return rc;
790bb30016cSlukem }
791bb30016cSlukem 
792bb30016cSlukem static int
nssov_db_init(BackendDB * be,ConfigReply * cr)793bb30016cSlukem nssov_db_init(
794bb30016cSlukem 	BackendDB *be,
795bb30016cSlukem 	ConfigReply *cr )
796bb30016cSlukem {
797bb30016cSlukem 	slap_overinst *on = (slap_overinst *)be->bd_info;
798bb30016cSlukem 	nssov_info *ni;
7994e6df137Slukem 	int rc;
800bb30016cSlukem 
8014e6df137Slukem 	rc = nssov_pam_init();
8024e6df137Slukem 	if (rc) return rc;
8034e6df137Slukem 
8044e6df137Slukem 	ni = ch_calloc( 1, sizeof(nssov_info) );
805bb30016cSlukem 	on->on_bi.bi_private = ni;
806bb30016cSlukem 
807bb30016cSlukem 	/* set up map keys */
808bb30016cSlukem 	nssov_alias_init(ni);
809bb30016cSlukem 	nssov_ether_init(ni);
810bb30016cSlukem 	nssov_group_init(ni);
811bb30016cSlukem 	nssov_host_init(ni);
812bb30016cSlukem 	nssov_netgroup_init(ni);
813bb30016cSlukem 	nssov_network_init(ni);
814bb30016cSlukem 	nssov_passwd_init(ni);
815bb30016cSlukem 	nssov_protocol_init(ni);
816bb30016cSlukem 	nssov_rpc_init(ni);
817bb30016cSlukem 	nssov_service_init(ni);
818bb30016cSlukem 	nssov_shadow_init(ni);
819bb30016cSlukem 
820bb30016cSlukem 	ni->ni_db = be->bd_self;
8214e6df137Slukem 	ni->ni_pam_opts = NI_PAM_UID2DN;
822bb30016cSlukem 
823bb30016cSlukem 	return 0;
824bb30016cSlukem }
825bb30016cSlukem 
826bb30016cSlukem static int
nssov_db_destroy(BackendDB * be,ConfigReply * cr)827bb30016cSlukem nssov_db_destroy(
828bb30016cSlukem 	BackendDB *be,
829bb30016cSlukem 	ConfigReply *cr )
830bb30016cSlukem {
8318bd9f7cdSchristos 	return 0;
832bb30016cSlukem }
833bb30016cSlukem 
834bb30016cSlukem static int
nssov_db_open(BackendDB * be,ConfigReply * cr)835bb30016cSlukem nssov_db_open(
836bb30016cSlukem 	BackendDB *be,
837bb30016cSlukem 	ConfigReply *cr )
838bb30016cSlukem {
839bb30016cSlukem 	slap_overinst *on = (slap_overinst *)be->bd_info;
840bb30016cSlukem 	nssov_info *ni = on->on_bi.bi_private;
841bb30016cSlukem 	nssov_mapinfo *mi;
842bb30016cSlukem 
843bb30016cSlukem 	int i, sock;
844bb30016cSlukem 	struct sockaddr_un addr;
845bb30016cSlukem 
846bb30016cSlukem 	/* Set default bases */
847bb30016cSlukem 	for (i=0; i<NM_NONE; i++) {
848bb30016cSlukem 		if ( BER_BVISNULL( &ni->ni_maps[i].mi_base )) {
849bb30016cSlukem 			ber_dupbv( &ni->ni_maps[i].mi_base, &be->be_nsuffix[0] );
850bb30016cSlukem 		}
851bb30016cSlukem 		if ( ni->ni_maps[i].mi_scope == LDAP_SCOPE_DEFAULT )
852bb30016cSlukem 			ni->ni_maps[i].mi_scope = LDAP_SCOPE_SUBTREE;
853bb30016cSlukem 	}
854bb30016cSlukem 	/* validate attribute maps */
855bb30016cSlukem 	mi = ni->ni_maps;
856bb30016cSlukem 	for ( i=0; i<NM_NONE; i++,mi++) {
857bb30016cSlukem 		const char *text;
858bb30016cSlukem 		int j;
859bb30016cSlukem 		for (j=0; !BER_BVISNULL(&mi->mi_attrkeys[j]); j++) {
860bb30016cSlukem 			/* skip attrs we already validated */
861bb30016cSlukem 			if ( mi->mi_attrs[j].an_desc ) continue;
862bb30016cSlukem 			if ( slap_bv2ad( &mi->mi_attrs[j].an_name,
863bb30016cSlukem 				&mi->mi_attrs[j].an_desc, &text )) {
864bb30016cSlukem 				Debug(LDAP_DEBUG_ANY,"nssov: invalid attr \"%s\": %s\n",
865*cf1d77f7Schristos 					mi->mi_attrs[j].an_name.bv_val, text );
866bb30016cSlukem 				return -1;
867bb30016cSlukem 			}
868bb30016cSlukem 		}
869bb30016cSlukem 		BER_BVZERO(&mi->mi_attrs[j].an_name);
870bb30016cSlukem 		mi->mi_attrs[j].an_desc = NULL;
871bb30016cSlukem 	}
872bb30016cSlukem 
8734e6df137Slukem 	/* Find host and authorizedService definitions */
8744e6df137Slukem 	if ((ni->ni_pam_opts & NI_PAM_USERHOST) && !nssov_pam_host_ad)
8754e6df137Slukem 	{
8764e6df137Slukem 		const char *text;
8774e6df137Slukem 		i = slap_str2ad("host", &nssov_pam_host_ad, &text);
8784e6df137Slukem 		if (i != LDAP_SUCCESS) {
8794e6df137Slukem 			Debug(LDAP_DEBUG_ANY,"nssov: host attr unknown: %s\n",
880*cf1d77f7Schristos 				text );
8814e6df137Slukem 			return -1;
8824e6df137Slukem 		}
8834e6df137Slukem 	}
8844e6df137Slukem 	if ((ni->ni_pam_opts & (NI_PAM_USERSVC|NI_PAM_HOSTSVC)) &&
8854e6df137Slukem 		!nssov_pam_svc_ad)
8864e6df137Slukem 	{
8874e6df137Slukem 		const char *text;
8884e6df137Slukem 		i = slap_str2ad("authorizedService", &nssov_pam_svc_ad, &text);
8894e6df137Slukem 		if (i != LDAP_SUCCESS) {
8904e6df137Slukem 			Debug(LDAP_DEBUG_ANY,"nssov: authorizedService attr unknown: %s\n",
891*cf1d77f7Schristos 				text );
8924e6df137Slukem 			return -1;
8934e6df137Slukem 		}
8944e6df137Slukem 	}
895bb30016cSlukem 	if ( slapMode & SLAP_SERVER_MODE ) {
896*cf1d77f7Schristos 		char ebuf[128];
8974e6df137Slukem 		/* make sure /var/run/nslcd exists */
8984e6df137Slukem 		if (mkdir(NSLCD_PATH, (mode_t) 0555)) {
899*cf1d77f7Schristos 			int saved_errno = errno;
9004e6df137Slukem 			Debug(LDAP_DEBUG_TRACE,"nssov: mkdir(%s) failed (ignored): %s\n",
901*cf1d77f7Schristos 					NSLCD_PATH, AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
9024e6df137Slukem 		} else {
903*cf1d77f7Schristos 			Debug(LDAP_DEBUG_TRACE,"nssov: created %s\n",NSLCD_PATH );
9044e6df137Slukem 		}
9054e6df137Slukem 
906bb30016cSlukem 		/* create a socket */
907bb30016cSlukem 		if ( (sock=socket(PF_UNIX,SOCK_STREAM,0))<0 )
908bb30016cSlukem 		{
909*cf1d77f7Schristos 			int saved_errno = errno;
910*cf1d77f7Schristos 			Debug(LDAP_DEBUG_ANY,"nssov: cannot create socket: %s\n",
911*cf1d77f7Schristos 					AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
912bb30016cSlukem 			return -1;
913bb30016cSlukem 		}
914bb30016cSlukem 		/* remove existing named socket */
915bb30016cSlukem 		if (unlink(NSLCD_SOCKET)<0)
916bb30016cSlukem 		{
917*cf1d77f7Schristos 			int saved_errno = errno;
9184e6df137Slukem 			Debug( LDAP_DEBUG_TRACE,"nssov: unlink() of "NSLCD_SOCKET" failed (ignored): %s\n",
919*cf1d77f7Schristos 							AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
920bb30016cSlukem 		}
921bb30016cSlukem 		/* create socket address structure */
922bb30016cSlukem 		memset(&addr,0,sizeof(struct sockaddr_un));
923bb30016cSlukem 		addr.sun_family=AF_UNIX;
924bb30016cSlukem 		strncpy(addr.sun_path,NSLCD_SOCKET,sizeof(addr.sun_path));
925bb30016cSlukem 		addr.sun_path[sizeof(addr.sun_path)-1]='\0';
926bb30016cSlukem 		/* bind to the named socket */
927bb30016cSlukem 		if (bind(sock,(struct sockaddr *)&addr,sizeof(struct sockaddr_un)))
928bb30016cSlukem 		{
929*cf1d77f7Schristos 			int saved_errno = errno;
930bb30016cSlukem 			Debug( LDAP_DEBUG_ANY,"nssov: bind() to "NSLCD_SOCKET" failed: %s",
931*cf1d77f7Schristos 				AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
932*cf1d77f7Schristos 			if (close(sock)) {
933*cf1d77f7Schristos 				saved_errno = errno;
934*cf1d77f7Schristos 				Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",
935*cf1d77f7Schristos 					AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
936*cf1d77f7Schristos 			}
937bb30016cSlukem 			return -1;
938bb30016cSlukem 		}
939bb30016cSlukem 		/* close the file descriptor on exit */
940bb30016cSlukem 		if (fcntl(sock,F_SETFD,FD_CLOEXEC)<0)
941bb30016cSlukem 		{
942*cf1d77f7Schristos 			int saved_errno = errno;
943*cf1d77f7Schristos 			Debug( LDAP_DEBUG_ANY,"nssov: fcntl(F_SETFL,O_NONBLOCK) failed: %s",
944*cf1d77f7Schristos 				AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
945*cf1d77f7Schristos 			if (close(sock)) {
946*cf1d77f7Schristos 				saved_errno = errno;
947*cf1d77f7Schristos 				Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",
948*cf1d77f7Schristos 					AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
949*cf1d77f7Schristos 			}
950bb30016cSlukem 			return -1;
951bb30016cSlukem 		}
952bb30016cSlukem 		/* set permissions of socket so anybody can do requests */
953bb30016cSlukem 		/* Note: we use chmod() here instead of fchmod() because
954bb30016cSlukem 			 fchmod does not work on sockets
955bb30016cSlukem 			 http://www.opengroup.org/onlinepubs/009695399/functions/fchmod.html
956bb30016cSlukem 			 http://lkml.org/lkml/2005/5/16/11 */
957bb30016cSlukem 		if (chmod(NSLCD_SOCKET,(mode_t)0666))
958bb30016cSlukem 		{
959*cf1d77f7Schristos 			int saved_errno = errno;
960*cf1d77f7Schristos 			Debug( LDAP_DEBUG_ANY,"nssov: chmod(0666) failed: %s",
961*cf1d77f7Schristos 				AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
962*cf1d77f7Schristos 			if (close(sock)) {
963*cf1d77f7Schristos 				saved_errno = errno;
964*cf1d77f7Schristos 				Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",
965*cf1d77f7Schristos 					AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
966*cf1d77f7Schristos 			}
967bb30016cSlukem 			return -1;
968bb30016cSlukem 		}
969bb30016cSlukem 		/* start listening for connections */
970bb30016cSlukem 		if (listen(sock,SOMAXCONN)<0)
971bb30016cSlukem 		{
972*cf1d77f7Schristos 			int saved_errno = errno;
973*cf1d77f7Schristos 			Debug( LDAP_DEBUG_ANY,"nssov: listen() failed: %s",
974*cf1d77f7Schristos 				AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
975*cf1d77f7Schristos 			if (close(sock)) {
976*cf1d77f7Schristos 				saved_errno = errno;
977*cf1d77f7Schristos 				Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",
978*cf1d77f7Schristos 					AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
979*cf1d77f7Schristos 			}
980bb30016cSlukem 			return -1;
981bb30016cSlukem 		}
982bb30016cSlukem 		ni->ni_socket = sock;
983bb30016cSlukem 		ni->ni_conn = connection_client_setup( sock, acceptconn, ni );
984bb30016cSlukem 	}
985bb30016cSlukem 
986bb30016cSlukem 	return 0;
987bb30016cSlukem }
988bb30016cSlukem 
989bb30016cSlukem static int
nssov_db_close(BackendDB * be,ConfigReply * cr)990bb30016cSlukem nssov_db_close(
991bb30016cSlukem 	BackendDB *be,
992bb30016cSlukem 	ConfigReply *cr )
993bb30016cSlukem {
994bb30016cSlukem 	slap_overinst *on = (slap_overinst *)be->bd_info;
995bb30016cSlukem 	nssov_info *ni = on->on_bi.bi_private;
996bb30016cSlukem 
99733197c6aStron 	if ( slapMode & SLAP_SERVER_MODE ) {
998*cf1d77f7Schristos 		char ebuf[128];
999bb30016cSlukem 		/* close socket if it's still in use */
1000*cf1d77f7Schristos 		if (ni->ni_socket >= 0)
1001bb30016cSlukem 		{
1002*cf1d77f7Schristos 			if (close(ni->ni_socket)) {
1003*cf1d77f7Schristos 				int saved_errno = errno;
1004*cf1d77f7Schristos 				Debug( LDAP_DEBUG_ANY,"problem closing server socket (ignored): %s",
1005*cf1d77f7Schristos 					AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
1006*cf1d77f7Schristos 			}
1007bb30016cSlukem 			ni->ni_socket = -1;
1008bb30016cSlukem 		}
1009bb30016cSlukem 		/* remove existing named socket */
1010bb30016cSlukem 		if (unlink(NSLCD_SOCKET)<0)
1011bb30016cSlukem 		{
1012*cf1d77f7Schristos 			int saved_errno = errno;
1013bb30016cSlukem 			Debug( LDAP_DEBUG_TRACE,"unlink() of "NSLCD_SOCKET" failed (ignored): %s",
1014*cf1d77f7Schristos 				AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
1015bb30016cSlukem 		}
1016bb30016cSlukem 	}
10178bd9f7cdSchristos 	return 0;
101833197c6aStron }
1019bb30016cSlukem 
1020bb30016cSlukem static slap_overinst nssov;
1021bb30016cSlukem 
1022bb30016cSlukem int
nssov_initialize(void)1023bb30016cSlukem nssov_initialize( void )
1024bb30016cSlukem {
1025bb30016cSlukem 	int rc;
1026bb30016cSlukem 
1027bb30016cSlukem 	nssov.on_bi.bi_type = "nssov";
1028bb30016cSlukem 	nssov.on_bi.bi_db_init = nssov_db_init;
1029bb30016cSlukem 	nssov.on_bi.bi_db_destroy = nssov_db_destroy;
1030bb30016cSlukem 	nssov.on_bi.bi_db_open = nssov_db_open;
1031bb30016cSlukem 	nssov.on_bi.bi_db_close = nssov_db_close;
1032bb30016cSlukem 
1033bb30016cSlukem 	nssov.on_bi.bi_cf_ocs = nssocs;
1034bb30016cSlukem 
1035bb30016cSlukem 	rc = config_register_schema( nsscfg, nssocs );
1036bb30016cSlukem 	if ( rc ) return rc;
1037bb30016cSlukem 
1038bb30016cSlukem 	return overlay_register(&nssov);
1039bb30016cSlukem }
1040bb30016cSlukem 
1041bb30016cSlukem #if SLAPD_OVER_NSSOV == SLAPD_MOD_DYNAMIC
1042bb30016cSlukem int
init_module(int argc,char * argv[])1043bb30016cSlukem init_module( int argc, char *argv[] )
1044bb30016cSlukem {
1045bb30016cSlukem 	return nssov_initialize();
1046bb30016cSlukem }
1047bb30016cSlukem #endif
1048