Home | History | Annotate | Line # | Download | only in nssov
      1 /*	$NetBSD: nssov.c,v 1.4 2025/09/05 21:16:17 christos Exp $	*/
      2 
      3 /* nssov.c - nss-ldap overlay for slapd */
      4 /* $OpenLDAP$ */
      5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      6  *
      7  * Copyright 2008-2024 The OpenLDAP Foundation.
      8  * Portions Copyright 2008 by Howard Chu, Symas Corp.
      9  * Portions Copyright 2013 by Ted C. Cheng, Symas Corp.
     10  * All rights reserved.
     11  *
     12  * Redistribution and use in source and binary forms, with or without
     13  * modification, are permitted only as authorized by the OpenLDAP
     14  * Public License.
     15  *
     16  * A copy of this license is available in the file LICENSE in the
     17  * top-level directory of the distribution or, alternatively, at
     18  * <http://www.OpenLDAP.org/license.html>.
     19  */
     20 /* ACKNOWLEDGEMENTS:
     21  * This code references portions of the nss-ldapd package
     22  * written by Arthur de Jong. The nss-ldapd code was forked
     23  * from the nss-ldap library written by Luke Howard.
     24  */
     25 
     26 #include "nssov.h"
     27 
     28 #ifndef SLAPD_OVER_NSSOV
     29 #define SLAPD_OVER_NSSOV SLAPD_MOD_DYNAMIC
     30 #endif
     31 
     32 #include "slap-config.h"
     33 
     34 #include "lutil.h"
     35 
     36 #include <ac/errno.h>
     37 #include <ac/unistd.h>
     38 #include <fcntl.h>
     39 #include <sys/stat.h>
     40 
     41 AttributeDescription *nssov_pam_host_ad;
     42 AttributeDescription *nssov_pam_svc_ad;
     43 
     44 /* buffer sizes for I/O */
     45 #define READBUFFER_MINSIZE 32
     46 #define READBUFFER_MAXSIZE 64
     47 #define WRITEBUFFER_MINSIZE 64
     48 #define WRITEBUFFER_MAXSIZE 64*1024
     49 
     50 /* Find the given attribute's value in the RDN of the DN */
     51 void nssov_find_rdnval(struct berval *dn, AttributeDescription *ad, struct berval *value)
     52 {
     53 	struct berval rdn;
     54 	char *next;
     55 
     56 	BER_BVZERO(value);
     57 	dnRdn( dn, &rdn );
     58 	do {
     59 		next = ber_bvchr( &rdn, '+' );
     60 		if ( rdn.bv_val[ad->ad_cname.bv_len] == '=' &&
     61 			!ber_bvcmp( &rdn, &ad->ad_cname )) {
     62 			if ( next )
     63 				rdn.bv_len = next - rdn.bv_val;
     64 			value->bv_val = rdn.bv_val + ad->ad_cname.bv_len + 1;
     65 			value->bv_len = rdn.bv_len - ad->ad_cname.bv_len - 1;
     66 			break;
     67 		}
     68 		if ( !next )
     69 			break;
     70 		next++;
     71 		rdn.bv_len -= next - rdn.bv_val;
     72 		rdn.bv_val = next;
     73 	} while (1);
     74 }
     75 
     76 /* create a search filter using a name that requires escaping */
     77 int nssov_filter_byname(nssov_mapinfo *mi,int key,struct berval *name,struct berval *buf)
     78 {
     79 	char buf2[1024];
     80 	struct berval bv2 = {sizeof(buf2),buf2};
     81 
     82 	/* escape attribute */
     83 	if (nssov_escape(name,&bv2))
     84 		return -1;
     85 	/* build filter */
     86 	if (bv2.bv_len + mi->mi_filter.bv_len + mi->mi_attrs[key].an_desc->ad_cname.bv_len + 6 >
     87 		buf->bv_len )
     88 		return -1;
     89 	buf->bv_len = snprintf(buf->bv_val, buf->bv_len, "(&%s(%s=%s))",
     90 		mi->mi_filter.bv_val, mi->mi_attrs[key].an_desc->ad_cname.bv_val,
     91 		bv2.bv_val );
     92 	return 0;
     93 }
     94 
     95 /* create a search filter using a string converted from an int */
     96 int nssov_filter_byid(nssov_mapinfo *mi,int key,struct berval *id,struct berval *buf)
     97 {
     98 	/* build filter */
     99 	if (id->bv_len + mi->mi_filter.bv_len + mi->mi_attrs[key].an_desc->ad_cname.bv_len + 6 >
    100 		buf->bv_len )
    101 		return -1;
    102 	buf->bv_len = snprintf(buf->bv_val, buf->bv_len, "(&%s(%s=%s))",
    103 		mi->mi_filter.bv_val, mi->mi_attrs[key].an_desc->ad_cname.bv_val,
    104 		id->bv_val );
    105 	return 0;
    106 }
    107 
    108 void get_userpassword(struct berval *attr,struct berval *pw)
    109 {
    110 	int i;
    111 	/* go over the entries and return the remainder of the value if it
    112 		 starts with {crypt} or crypt$ */
    113 	for (i=0;!BER_BVISNULL(&attr[i]);i++)
    114 	{
    115 		if (strncasecmp(attr[i].bv_val,"{crypt}",7)==0) {
    116 			pw->bv_val = attr[i].bv_val + 7;
    117 			pw->bv_len = attr[i].bv_len - 7;
    118 			return;
    119 		}
    120 		if (strncasecmp(attr[i].bv_val,"crypt$",6)==0) {
    121 			pw->bv_val = attr[i].bv_val + 6;
    122 			pw->bv_len = attr[i].bv_len - 6;
    123 			return;
    124 		}
    125 	}
    126 	/* just return the first value completely */
    127 	*pw = *attr;
    128 	/* TODO: support more password formats e.g. SMD5
    129 		(which is $1$ but in a different format)
    130 		(any code for this is more than welcome) */
    131 }
    132 
    133 /* this writes a single address to the stream */
    134 int write_address(TFILE *fp,struct berval *addr)
    135 {
    136 	int32_t tmpint32;
    137 	struct in_addr ipv4addr;
    138 	struct in6_addr ipv6addr;
    139 	/* try to parse the address as IPv4 first, fall back to IPv6 */
    140 	if (inet_pton(AF_INET,addr->bv_val,&ipv4addr)>0)
    141 	{
    142 		/* write address type */
    143 		WRITE_INT32(fp,AF_INET);
    144 		/* write the address length */
    145 		WRITE_INT32(fp,sizeof(struct in_addr));
    146 		/* write the address itself (in network byte order) */
    147 		WRITE(fp,&ipv4addr,sizeof(struct in_addr));
    148 	}
    149 	else if (inet_pton(AF_INET6,addr->bv_val,&ipv6addr)>0)
    150 	{
    151 		/* write address type */
    152 		WRITE_INT32(fp,AF_INET6);
    153 		/* write the address length */
    154 		WRITE_INT32(fp,sizeof(struct in6_addr));
    155 		/* write the address itself (in network byte order) */
    156 		WRITE(fp,&ipv6addr,sizeof(struct in6_addr));
    157 	}
    158 	else
    159 	{
    160 		/* failure, log but write simple invalid address
    161 			 (otherwise the address list is messed up) */
    162 		/* TODO: have error message in correct format */
    163 		Debug(LDAP_DEBUG_ANY,"nssov: unparsable address: %s\n",addr->bv_val );
    164 		/* write an illegal address type */
    165 		WRITE_INT32(fp,-1);
    166 		/* write an empty address */
    167 		WRITE_INT32(fp,0);
    168 	}
    169 	/* we're done */
    170 	return 0;
    171 }
    172 
    173 int read_address(TFILE *fp,char *addr,int *addrlen,int *af)
    174 {
    175 	int32_t tmpint32;
    176 	int len;
    177 	/* read address family */
    178 	READ_INT32(fp,*af);
    179 	if ((*af!=AF_INET)&&(*af!=AF_INET6))
    180 	{
    181 		Debug(LDAP_DEBUG_ANY,"nssov: incorrect address family specified: %d\n",*af );
    182 		return -1;
    183 	}
    184 	/* read address length */
    185 	READ_INT32(fp,len);
    186 	if ((len>*addrlen)||(len<=0))
    187 	{
    188 		Debug(LDAP_DEBUG_ANY,"nssov: address length incorrect: %d\n",len );
    189 		return -1;
    190 	}
    191 	*addrlen=len;
    192 	/* read address */
    193 	READ(fp,addr,len);
    194 	/* we're done */
    195 	return 0;
    196 }
    197 
    198 int nssov_escape(struct berval *src,struct berval *dst)
    199 {
    200 	size_t pos=0;
    201 	int i;
    202 	/* go over all characters in source string */
    203 	for (i=0;i<src->bv_len;i++)
    204 	{
    205 		/* check if char will fit */
    206 		if (pos>=(dst->bv_len-4))
    207 			return -1;
    208 		/* do escaping for some characters */
    209 		switch (src->bv_val[i])
    210 		{
    211 			case '*':
    212 				strcpy(dst->bv_val+pos,"\\2a");
    213 				pos+=3;
    214 				break;
    215 			case '(':
    216 				strcpy(dst->bv_val+pos,"\\28");
    217 				pos+=3;
    218 				break;
    219 			case ')':
    220 				strcpy(dst->bv_val+pos,"\\29");
    221 				pos+=3;
    222 				break;
    223 			case '\\':
    224 				strcpy(dst->bv_val+pos,"\\5c");
    225 				pos+=3;
    226 				break;
    227 			default:
    228 				/* just copy character */
    229 				dst->bv_val[pos++]=src->bv_val[i];
    230 				break;
    231 		}
    232 	}
    233 	/* terminate destination string */
    234 	dst->bv_val[pos]='\0';
    235 	dst->bv_len = pos;
    236 	return 0;
    237 }
    238 
    239 /* read the version information and action from the stream
    240    this function returns the read action in location pointer to by action */
    241 static int read_header(TFILE *fp,int32_t *action)
    242 {
    243   int32_t tmpint32;
    244   /* read the protocol version */
    245   READ_INT32(fp,tmpint32);
    246   if (tmpint32 != (int32_t)NSLCD_VERSION)
    247   {
    248     Debug( LDAP_DEBUG_TRACE,"nssov: wrong nslcd version id (%d)\n",(int)tmpint32 );
    249     return -1;
    250   }
    251   /* read the request type */
    252   READ_INT32(fp,*action);
    253   return 0;
    254 }
    255 
    256 int nssov_config(nssov_info *ni,TFILE *fp,Operation *op)
    257 {
    258 	int opt;
    259 	int32_t tmpint32;
    260 
    261 	READ_INT32(fp,opt);
    262 
    263 	Debug(LDAP_DEBUG_TRACE, "nssov_config (%d)\n",opt );
    264 
    265 	WRITE_INT32(fp,NSLCD_VERSION);
    266 	WRITE_INT32(fp,NSLCD_ACTION_CONFIG_GET);
    267 	WRITE_INT32(fp,NSLCD_RESULT_BEGIN);
    268 
    269 	switch (opt) {
    270 	case NSLCD_CONFIG_PAM_PASSWORD_PROHIBIT_MESSAGE:
    271 		/* request for pam password_prohibit_message */
    272 		/* nssov_pam prohibits password  */
    273 		if (!BER_BVISEMPTY(&ni->ni_pam_password_prohibit_message)) {
    274 			Debug(LDAP_DEBUG_TRACE,"nssov_config(): %s (%s)\n",
    275 				"password_prohibit_message",
    276 				ni->ni_pam_password_prohibit_message.bv_val );
    277 			WRITE_STRING(fp,ni->ni_pam_password_prohibit_message.bv_val);
    278 		}
    279 	default:
    280 		/* all other config options are ignored */
    281 		break;
    282 	}
    283 
    284 	WRITE_INT32(fp,NSLCD_RESULT_END);
    285 	return 0;
    286 }
    287 
    288 
    289 /* read a request message, returns <0 in case of errors,
    290    this function closes the socket */
    291 static void handleconnection(nssov_info *ni,int sock,Operation *op)
    292 {
    293   TFILE *fp;
    294   int32_t action;
    295   int readtimeout,writetimeout;
    296   uid_t uid;
    297   gid_t gid;
    298   char authid[sizeof("gidNumber=4294967295+uidNumber=424967295,cn=peercred,cn=external,cn=auth")];
    299   char peerbuf[8];
    300   struct berval peerbv = { sizeof(peerbuf), peerbuf };
    301 
    302   /* log connection */
    303   if (LUTIL_GETPEEREID(sock,&uid,&gid,&peerbv)) {
    304     char ebuf[128];
    305     int saved_errno = errno;
    306     Debug( LDAP_DEBUG_TRACE,"nssov: connection from unknown client: %s\n",
    307                       AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
    308   } else {
    309     Debug( LDAP_DEBUG_TRACE,"nssov: connection from uid=%d gid=%d\n",
    310                       (int)uid,(int)gid );
    311   }
    312 
    313   /* Should do authid mapping too */
    314   op->o_dn.bv_len = sprintf(authid,"gidNumber=%d+uidNumber=%d,cn=peercred,cn=external,cn=auth",
    315 	(int)gid, (int)uid );
    316   op->o_dn.bv_val = authid;
    317   op->o_ndn = op->o_dn;
    318 
    319   /* set the timeouts:
    320    * read timeout is half a second because clients should send their request
    321    * quickly, write timeout is 60 seconds because clients could be taking some
    322    * time to process the results
    323    */
    324   readtimeout = 500;
    325   writetimeout = 60000;
    326   /* create a stream object */
    327   if ((fp=tio_fdopen(sock,readtimeout,writetimeout,
    328                      READBUFFER_MINSIZE,READBUFFER_MAXSIZE,
    329                      WRITEBUFFER_MINSIZE,WRITEBUFFER_MAXSIZE))==NULL)
    330   {
    331     char ebuf[128];
    332     int saved_errno = errno;
    333     Debug( LDAP_DEBUG_ANY,"nssov: cannot create stream for writing: %s",
    334                       AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
    335     (void)close(sock);
    336     return;
    337   }
    338   /* read request */
    339   if (read_header(fp,&action))
    340   {
    341     (void)tio_close(fp);
    342     return;
    343   }
    344   /* handle request */
    345   switch (action)
    346   {
    347     case NSLCD_ACTION_ALIAS_BYNAME:     (void)nssov_alias_byname(ni,fp,op); break;
    348     case NSLCD_ACTION_ALIAS_ALL:        (void)nssov_alias_all(ni,fp,op); break;
    349     case NSLCD_ACTION_ETHER_BYNAME:     (void)nssov_ether_byname(ni,fp,op); break;
    350     case NSLCD_ACTION_ETHER_BYETHER:    (void)nssov_ether_byether(ni,fp,op); break;
    351     case NSLCD_ACTION_ETHER_ALL:        (void)nssov_ether_all(ni,fp,op); break;
    352     case NSLCD_ACTION_GROUP_BYNAME:     (void)nssov_group_byname(ni,fp,op); break;
    353     case NSLCD_ACTION_GROUP_BYGID:      (void)nssov_group_bygid(ni,fp,op); break;
    354     case NSLCD_ACTION_GROUP_BYMEMBER:   (void)nssov_group_bymember(ni,fp,op); break;
    355     case NSLCD_ACTION_GROUP_ALL:        (void)nssov_group_all(ni,fp,op); break;
    356     case NSLCD_ACTION_HOST_BYNAME:      (void)nssov_host_byname(ni,fp,op); break;
    357     case NSLCD_ACTION_HOST_BYADDR:      (void)nssov_host_byaddr(ni,fp,op); break;
    358     case NSLCD_ACTION_HOST_ALL:         (void)nssov_host_all(ni,fp,op); break;
    359     case NSLCD_ACTION_NETGROUP_BYNAME:  (void)nssov_netgroup_byname(ni,fp,op); break;
    360     case NSLCD_ACTION_NETWORK_BYNAME:   (void)nssov_network_byname(ni,fp,op); break;
    361     case NSLCD_ACTION_NETWORK_BYADDR:   (void)nssov_network_byaddr(ni,fp,op); break;
    362     case NSLCD_ACTION_NETWORK_ALL:      (void)nssov_network_all(ni,fp,op); break;
    363     case NSLCD_ACTION_PASSWD_BYNAME:    (void)nssov_passwd_byname(ni,fp,op); break;
    364     case NSLCD_ACTION_PASSWD_BYUID:     (void)nssov_passwd_byuid(ni,fp,op); break;
    365     case NSLCD_ACTION_PASSWD_ALL:       (void)nssov_passwd_all(ni,fp,op); break;
    366     case NSLCD_ACTION_PROTOCOL_BYNAME:  (void)nssov_protocol_byname(ni,fp,op); break;
    367     case NSLCD_ACTION_PROTOCOL_BYNUMBER:(void)nssov_protocol_bynumber(ni,fp,op); break;
    368     case NSLCD_ACTION_PROTOCOL_ALL:     (void)nssov_protocol_all(ni,fp,op); break;
    369     case NSLCD_ACTION_RPC_BYNAME:       (void)nssov_rpc_byname(ni,fp,op); break;
    370     case NSLCD_ACTION_RPC_BYNUMBER:     (void)nssov_rpc_bynumber(ni,fp,op); break;
    371     case NSLCD_ACTION_RPC_ALL:          (void)nssov_rpc_all(ni,fp,op); break;
    372     case NSLCD_ACTION_SERVICE_BYNAME:   (void)nssov_service_byname(ni,fp,op); break;
    373     case NSLCD_ACTION_SERVICE_BYNUMBER: (void)nssov_service_bynumber(ni,fp,op); break;
    374     case NSLCD_ACTION_SERVICE_ALL:      (void)nssov_service_all(ni,fp,op); break;
    375     case NSLCD_ACTION_SHADOW_BYNAME:    if (uid==0) (void)nssov_shadow_byname(ni,fp,op); break;
    376     case NSLCD_ACTION_SHADOW_ALL:       if (uid==0) (void)nssov_shadow_all(ni,fp,op); break;
    377 	case NSLCD_ACTION_PAM_AUTHC:		(void)pam_authc(ni,fp,op,uid); break;
    378 	case NSLCD_ACTION_PAM_AUTHZ:		(void)pam_authz(ni,fp,op); break;
    379 	case NSLCD_ACTION_PAM_SESS_O:		if (uid==0) (void)pam_sess_o(ni,fp,op); break;
    380 	case NSLCD_ACTION_PAM_SESS_C:		if (uid==0) (void)pam_sess_c(ni,fp,op); break;
    381 	case NSLCD_ACTION_PAM_PWMOD:		(void)pam_pwmod(ni,fp,op,uid); break;
    382 	case NSLCD_ACTION_CONFIG_GET:			(void)nssov_config(ni,fp,op); break;
    383     default:
    384       Debug( LDAP_DEBUG_ANY,"nssov: invalid request id: %d",(int)action );
    385       break;
    386   }
    387   /* we're done with the request */
    388   (void)tio_close(fp);
    389   return;
    390 }
    391 
    392 /* accept a connection on the socket */
    393 static void *acceptconn(void *ctx, void *arg)
    394 {
    395 	nssov_info *ni = arg;
    396 	Connection conn = {0};
    397 	OperationBuffer opbuf;
    398 	Operation *op;
    399 	int csock;
    400 
    401 	if ( slapd_shutdown )
    402 		return NULL;
    403 
    404 	{
    405 		struct sockaddr_storage addr;
    406 		socklen_t alen;
    407 		int j;
    408 
    409 		/* accept a new connection */
    410 		alen=(socklen_t)sizeof(struct sockaddr_storage);
    411 		csock=accept(ni->ni_socket,(struct sockaddr *)&addr,&alen);
    412 		connection_client_enable(ni->ni_conn);
    413 		if (csock<0)
    414 		{
    415 			char ebuf[128];
    416 			int saved_errno = errno;
    417 			if ((errno==EINTR)||(errno==EAGAIN)||(errno==EWOULDBLOCK))
    418 			{
    419 				Debug( LDAP_DEBUG_TRACE,"nssov: accept() failed (ignored): %s",
    420 					AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
    421 				return NULL;
    422 			}
    423 			Debug( LDAP_DEBUG_ANY,"nssov: accept() failed: %s",
    424 				AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
    425 			return NULL;
    426 		}
    427 		/* make sure O_NONBLOCK is not inherited */
    428 		if ((j=fcntl(csock,F_GETFL,0))<0)
    429 		{
    430 			char ebuf[128];
    431 			int saved_errno = errno;
    432 			Debug( LDAP_DEBUG_ANY,"nssov: fcntl(F_GETFL) failed: %s",
    433 				AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
    434 			if (close(csock)) {
    435 				saved_errno = errno;
    436 				Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",
    437 					AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
    438 			}
    439 			return NULL;
    440 		}
    441 		if (fcntl(csock,F_SETFL,j&~O_NONBLOCK)<0)
    442 		{
    443 			char ebuf[128];
    444 			int saved_errno = errno;
    445 			Debug( LDAP_DEBUG_ANY,"nssov: fcntl(F_SETFL,~O_NONBLOCK) failed: %s",
    446 				AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
    447 			if (close(csock)) {
    448 				saved_errno = errno;
    449 				Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",
    450 					AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
    451 			}
    452 			return NULL;
    453 		}
    454 	}
    455 	connection_fake_init( &conn, &opbuf, ctx );
    456 	op=&opbuf.ob_op;
    457 	conn.c_ssf = conn.c_transport_ssf = local_ssf;
    458 	op->o_bd = ni->ni_db;
    459 	op->o_tag = LDAP_REQ_SEARCH;
    460 
    461 	/* handle the connection */
    462 	handleconnection(ni,csock,op);
    463 
    464 	return NULL;
    465 }
    466 
    467 static slap_verbmasks nss_svcs[] = {
    468 	{ BER_BVC("aliases"), NM_alias },
    469 	{ BER_BVC("ethers"), NM_ether },
    470 	{ BER_BVC("group"), NM_group },
    471 	{ BER_BVC("hosts"), NM_host },
    472 	{ BER_BVC("netgroup"), NM_netgroup },
    473 	{ BER_BVC("networks"), NM_network },
    474 	{ BER_BVC("passwd"), NM_passwd },
    475 	{ BER_BVC("protocols"), NM_protocol },
    476 	{ BER_BVC("rpc"), NM_rpc },
    477 	{ BER_BVC("services"), NM_service },
    478 	{ BER_BVC("shadow"), NM_shadow },
    479 	{ BER_BVNULL, 0 }
    480 };
    481 
    482 static slap_verbmasks pam_opts[] = {
    483 	{ BER_BVC("userhost"), NI_PAM_USERHOST },
    484 	{ BER_BVC("userservice"), NI_PAM_USERSVC },
    485 	{ BER_BVC("usergroup"), NI_PAM_USERGRP },
    486 	{ BER_BVC("hostservice"), NI_PAM_HOSTSVC },
    487 	{ BER_BVC("authz2dn"), NI_PAM_SASL2DN },
    488 	{ BER_BVC("uid2dn"), NI_PAM_UID2DN },
    489 	{ BER_BVNULL, 0 }
    490 };
    491 
    492 enum {
    493 	NSS_SSD=1,
    494 	NSS_MAP,
    495 	NSS_PAM,
    496 	NSS_PAMGROUP,
    497 	NSS_PAMSESS
    498 };
    499 
    500 static ConfigDriver nss_cf_gen;
    501 
    502 static ConfigTable nsscfg[] = {
    503 	{ "nssov-ssd", "service> <url", 3, 3, 0, ARG_MAGIC|NSS_SSD,
    504 		nss_cf_gen, "(OLcfgCtAt:3.1 NAME 'olcNssSsd' "
    505 			"DESC 'URL for searches in a given service' "
    506 			"EQUALITY caseIgnoreMatch "
    507 			"SYNTAX OMsDirectoryString )", NULL, NULL },
    508 	{ "nssov-map", "service> <orig> <new", 4, 4, 0, ARG_MAGIC|NSS_MAP,
    509 		nss_cf_gen, "(OLcfgCtAt:3.2 NAME 'olcNssMap' "
    510 			"DESC 'Map <service> lookups of <orig> attr to <new> attr' "
    511 			"EQUALITY caseIgnoreMatch "
    512 			"SYNTAX OMsDirectoryString )", NULL, NULL },
    513 	{ "nssov-pam", "options", 2, 0, 0, ARG_MAGIC|NSS_PAM,
    514 		nss_cf_gen, "(OLcfgCtAt:3.3 NAME 'olcNssPam' "
    515 			"DESC 'PAM authentication and authorization options' "
    516 			"EQUALITY caseIgnoreMatch "
    517 			"SYNTAX OMsDirectoryString )", NULL, NULL },
    518 	{ "nssov-pam-defhost", "hostname", 2, 2, 0, ARG_OFFSET|ARG_BERVAL,
    519 		(void *)offsetof(struct nssov_info, ni_pam_defhost),
    520 		"(OLcfgCtAt:3.4 NAME 'olcNssPamDefHost' "
    521 			"DESC 'Default hostname for service checks' "
    522 			"EQUALITY caseIgnoreMatch "
    523 			"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
    524 	{ "nssov-pam-group-dn", "DN", 2, 2, 0, ARG_MAGIC|ARG_DN|NSS_PAMGROUP,
    525 		nss_cf_gen, "(OLcfgCtAt:3.5 NAME 'olcNssPamGroupDN' "
    526 			"DESC 'DN of group in which membership is required' "
    527 			"EQUALITY distinguishedNameMatch "
    528 			"SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
    529 	{ "nssov-pam-group-ad", "attr", 2, 2, 0, ARG_OFFSET|ARG_ATDESC,
    530 		(void *)offsetof(struct nssov_info, ni_pam_group_ad),
    531 		"(OLcfgCtAt:3.6 NAME 'olcNssPamGroupAD' "
    532 			"DESC 'Member attribute to use for group check' "
    533 			"EQUALITY caseIgnoreMatch "
    534 			"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
    535 	{ "nssov-pam-min-uid", "uid", 2, 2, 0, ARG_OFFSET|ARG_INT,
    536 		(void *)offsetof(struct nssov_info, ni_pam_min_uid),
    537 		"(OLcfgCtAt:3.7 NAME 'olcNssPamMinUid' "
    538 			"DESC 'Minimum UID allowed to login' "
    539 			"EQUALITY integerMatch "
    540 			"SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
    541 	{ "nssov-pam-max-uid", "uid", 2, 2, 0, ARG_OFFSET|ARG_INT,
    542 		(void *)offsetof(struct nssov_info, ni_pam_max_uid),
    543 		"(OLcfgCtAt:3.8 NAME 'olcNssPamMaxUid' "
    544 			"DESC 'Maximum UID allowed to login' "
    545 			"EQUALITY integerMatch "
    546 			"SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
    547 	{ "nssov-pam-template-ad", "attr", 2, 2, 0, ARG_OFFSET|ARG_ATDESC,
    548 		(void *)offsetof(struct nssov_info, ni_pam_template_ad),
    549 		"(OLcfgCtAt:3.9 NAME 'olcNssPamTemplateAD' "
    550 			"DESC 'Attribute to use for template login name' "
    551 			"EQUALITY caseIgnoreMatch "
    552 			"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
    553 	{ "nssov-pam-template", "name", 2, 2, 0, ARG_OFFSET|ARG_BERVAL,
    554 		(void *)offsetof(struct nssov_info, ni_pam_template),
    555 		"(OLcfgCtAt:3.10 NAME 'olcNssPamTemplate' "
    556 			"DESC 'Default template login name' "
    557 			"EQUALITY caseIgnoreMatch "
    558 			"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
    559 	{ "nssov-pam-session", "service", 2, 2, 0, ARG_MAGIC|NSS_PAMSESS,
    560 		nss_cf_gen, "(OLcfgCtAt:3.11 NAME 'olcNssPamSession' "
    561 			"DESC 'Services for which sessions will be recorded' "
    562 			"EQUALITY caseIgnoreMatch "
    563 			"SYNTAX OMsDirectoryString )", NULL, NULL },
    564 	{ "nssov-pam-password-prohibit-message",
    565 		"password_prohibit_message", 2, 2, 0,
    566 		ARG_OFFSET|ARG_BERVAL,
    567 		(void *)offsetof(struct nssov_info, ni_pam_password_prohibit_message),
    568 		"(OLcfgCtAt:3.12 NAME 'olcNssPamPwdProhibitMsg' "
    569 			"DESC 'Prohibit password modification message' "
    570 			"EQUALITY caseIgnoreMatch "
    571 			"SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
    572 	{ "nssov-pam-pwdmgr-dn",
    573 		"pwdmgr_dn", 2, 2, 0,
    574 		ARG_OFFSET|ARG_BERVAL,
    575 		(void *)offsetof(struct nssov_info, ni_pam_pwdmgr_dn),
    576 		"(OLcfgCtAt:3.13 NAME 'olcPamPwdmgrDn' "
    577 			"DESC 'Password Manager DN' "
    578 			"EQUALITY distinguishedNameMatch "
    579 			"SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
    580 	{ "nssov-pam-pwdmgr-pwd",
    581 		"pwdmgr_pwd", 2, 2, 0,
    582 		ARG_OFFSET|ARG_BERVAL,
    583 		(void *)offsetof(struct nssov_info, ni_pam_pwdmgr_pwd),
    584 		"(OLcfgCtAt:3.14 NAME 'olcPamPwdmgrPwd' "
    585 			"DESC 'Password Manager Pwd' "
    586 			"EQUALITY octetStringMatch "
    587 			"SYNTAX OMsOctetString SINGLE-VALUE )", NULL, NULL },
    588 	{ NULL, NULL, 0,0,0, ARG_IGNORED }
    589 };
    590 
    591 static ConfigOCs nssocs[] = {
    592 	{ "( OLcfgCtOc:3.1 "
    593 		"NAME 'olcNssOvConfig' "
    594 		"DESC 'NSS lookup configuration' "
    595 		"SUP olcOverlayConfig "
    596 		"MAY ( olcNssSsd $ olcNssMap $ olcNssPam $ olcNssPamDefHost $ "
    597 			"olcNssPamGroupDN $ olcNssPamGroupAD $ "
    598 			"olcNssPamMinUid $ olcNssPamMaxUid $ olcNssPamSession $ "
    599 			"olcNssPamTemplateAD $ olcNssPamTemplate ) )",
    600 		Cft_Overlay, nsscfg },
    601 	{ NULL, 0, NULL }
    602 };
    603 
    604 static int
    605 nss_cf_gen(ConfigArgs *c)
    606 {
    607 	slap_overinst *on = (slap_overinst *)c->bi;
    608 	nssov_info *ni = on->on_bi.bi_private;
    609 	nssov_mapinfo *mi;
    610 	int i, j, rc = 0;
    611 	slap_mask_t m;
    612 
    613 	if ( c->op == SLAP_CONFIG_EMIT ) {
    614 		switch(c->type) {
    615 		case NSS_SSD:
    616 			rc = 1;
    617 			for (i=NM_alias;i<NM_NONE;i++) {
    618 				struct berval scope;
    619 				struct berval ssd;
    620 				struct berval base;
    621 
    622 				mi = &ni->ni_maps[i];
    623 
    624 				/* ignore all-default services */
    625 				if ( mi->mi_scope == LDAP_SCOPE_DEFAULT &&
    626 					bvmatch( &mi->mi_filter, &mi->mi_filter0 ) &&
    627 					BER_BVISNULL( &mi->mi_base ))
    628 					continue;
    629 
    630 				if ( BER_BVISNULL( &mi->mi_base ))
    631 					base = ni->ni_db->be_nsuffix[0];
    632 				else
    633 					base = mi->mi_base;
    634 				ldap_pvt_scope2bv(mi->mi_scope == LDAP_SCOPE_DEFAULT ?
    635 					LDAP_SCOPE_SUBTREE : mi->mi_scope, &scope);
    636 				ssd.bv_len = STRLENOF(" ldap:///???") + nss_svcs[i].word.bv_len +
    637 					base.bv_len + scope.bv_len + mi->mi_filter.bv_len;
    638 				ssd.bv_val = ch_malloc( ssd.bv_len + 1 );
    639 				sprintf(ssd.bv_val, "%s ldap:///%s??%s?%s", nss_svcs[i].word.bv_val,
    640 					base.bv_val, scope.bv_val, mi->mi_filter.bv_val );
    641 				ber_bvarray_add( &c->rvalue_vals, &ssd );
    642 				rc = 0;
    643 			}
    644 			break;
    645 		case NSS_MAP:
    646 			rc = 1;
    647 			for (i=NM_alias;i<NM_NONE;i++) {
    648 
    649 				mi = &ni->ni_maps[i];
    650 				for (j=0;!BER_BVISNULL(&mi->mi_attrkeys[j]);j++) {
    651 					if ( ber_bvstrcasecmp(&mi->mi_attrkeys[j],
    652 						&mi->mi_attrs[j].an_name)) {
    653 						struct berval map;
    654 
    655 						map.bv_len = nss_svcs[i].word.bv_len +
    656 							mi->mi_attrkeys[j].bv_len +
    657 							mi->mi_attrs[j].an_desc->ad_cname.bv_len + 2;
    658 						map.bv_val = ch_malloc(map.bv_len + 1);
    659 						sprintf(map.bv_val, "%s %s %s", nss_svcs[i].word.bv_val,
    660 							mi->mi_attrkeys[j].bv_val, mi->mi_attrs[j].an_desc->ad_cname.bv_val );
    661 						ber_bvarray_add( &c->rvalue_vals, &map );
    662 						rc = 0;
    663 					}
    664 				}
    665 			}
    666 			break;
    667 		case NSS_PAM:
    668 			rc = mask_to_verbs( pam_opts, ni->ni_pam_opts, &c->rvalue_vals );
    669 			break;
    670 		case NSS_PAMGROUP:
    671 			if (!BER_BVISEMPTY( &ni->ni_pam_group_dn )) {
    672 				value_add_one( &c->rvalue_vals, &ni->ni_pam_group_dn );
    673 				value_add_one( &c->rvalue_nvals, &ni->ni_pam_group_dn );
    674 			} else {
    675 				rc = 1;
    676 			}
    677 			break;
    678 		case NSS_PAMSESS:
    679 			if (ni->ni_pam_sessions) {
    680 				ber_bvarray_dup_x( &c->rvalue_vals, ni->ni_pam_sessions, NULL );
    681 			} else {
    682 				rc = 1;
    683 			}
    684 			break;
    685 		}
    686 		return rc;
    687 	} else if ( c->op == LDAP_MOD_DELETE ) {
    688 		/* FIXME */
    689 		return 1;
    690 	}
    691 	switch( c->type ) {
    692 	case NSS_SSD: {
    693 		LDAPURLDesc *lud;
    694 
    695 		i = verb_to_mask(c->argv[1], nss_svcs);
    696 		if ( i == NM_NONE )
    697 			return 1;
    698 
    699 		mi = &ni->ni_maps[i];
    700 		rc = ldap_url_parse(c->argv[2], &lud);
    701 		if ( rc )
    702 			return 1;
    703 		do {
    704 			struct berval base;
    705 			/* Must be LDAP scheme */
    706 			if (strcasecmp(lud->lud_scheme,"ldap")) {
    707 				rc = 1;
    708 				break;
    709 			}
    710 			/* Host part, attrs, and extensions must be empty */
    711 			if (( lud->lud_host && *lud->lud_host ) ||
    712 				lud->lud_attrs || lud->lud_exts ) {
    713 				rc = 1;
    714 				break;
    715 			}
    716 			ber_str2bv( lud->lud_dn,0,0,&base);
    717 			rc = dnNormalize( 0,NULL,NULL,&base,&mi->mi_base,NULL);
    718 			if ( rc )
    719 				break;
    720 			if ( lud->lud_filter ) {
    721 				/* steal this */
    722 				ber_str2bv( lud->lud_filter,0,0,&mi->mi_filter);
    723 				lud->lud_filter = NULL;
    724 			}
    725 			mi->mi_scope = lud->lud_scope;
    726 		} while(0);
    727 		ldap_free_urldesc( lud );
    728 		}
    729 		break;
    730 	case NSS_MAP:
    731 		i = verb_to_mask(c->argv[1], nss_svcs);
    732 		if ( i == NM_NONE )
    733 			return 1;
    734 		rc = 1;
    735 		mi = &ni->ni_maps[i];
    736 		for (j=0; !BER_BVISNULL(&mi->mi_attrkeys[j]); j++) {
    737 			if (!strcasecmp(c->argv[2],mi->mi_attrkeys[j].bv_val)) {
    738 				AttributeDescription *ad = NULL;
    739 				const char *text;
    740 				rc = slap_str2ad( c->argv[3], &ad, &text);
    741 				if ( rc == 0 ) {
    742 					mi->mi_attrs[j].an_desc = ad;
    743 					mi->mi_attrs[j].an_name = ad->ad_cname;
    744 				}
    745 				break;
    746 			}
    747 		}
    748 		break;
    749 	case NSS_PAM:
    750 		m = ni->ni_pam_opts;
    751 		i = verbs_to_mask(c->argc, c->argv, pam_opts, &m);
    752 		if (i == 0) {
    753 			ni->ni_pam_opts = m;
    754 			if ((m & NI_PAM_USERHOST) && !nssov_pam_host_ad) {
    755 				const char *text;
    756 				i = slap_str2ad("host", &nssov_pam_host_ad, &text);
    757 				if (i != LDAP_SUCCESS) {
    758 					snprintf(c->cr_msg, sizeof(c->cr_msg),
    759 						"nssov: host attr unknown: %s", text);
    760 					Debug(LDAP_DEBUG_ANY,"%s\n",c->cr_msg );
    761 					rc = 1;
    762 					break;
    763 				}
    764 			}
    765 			if ((m & (NI_PAM_USERSVC|NI_PAM_HOSTSVC)) && !nssov_pam_svc_ad) {
    766 				const char *text;
    767 				i = slap_str2ad("authorizedService", &nssov_pam_svc_ad, &text);
    768 				if (i != LDAP_SUCCESS) {
    769 					snprintf(c->cr_msg, sizeof(c->cr_msg),
    770 						"nssov: authorizedService attr unknown: %s", text);
    771 					Debug(LDAP_DEBUG_ANY,"%s\n",c->cr_msg );
    772 					rc = 1;
    773 					break;
    774 				}
    775 			}
    776 		} else {
    777 			rc = 1;
    778 		}
    779 		break;
    780 	case NSS_PAMGROUP:
    781 		ni->ni_pam_group_dn = c->value_ndn;
    782 		ch_free( c->value_dn.bv_val );
    783 		break;
    784 	case NSS_PAMSESS:
    785 		ber_str2bv( c->argv[1], 0, 1, &c->value_bv );
    786 		ber_bvarray_add( &ni->ni_pam_sessions, &c->value_bv );
    787 		break;
    788 	}
    789 	return rc;
    790 }
    791 
    792 static int
    793 nssov_db_init(
    794 	BackendDB *be,
    795 	ConfigReply *cr )
    796 {
    797 	slap_overinst *on = (slap_overinst *)be->bd_info;
    798 	nssov_info *ni;
    799 	int rc;
    800 
    801 	rc = nssov_pam_init();
    802 	if (rc) return rc;
    803 
    804 	ni = ch_calloc( 1, sizeof(nssov_info) );
    805 	on->on_bi.bi_private = ni;
    806 
    807 	/* set up map keys */
    808 	nssov_alias_init(ni);
    809 	nssov_ether_init(ni);
    810 	nssov_group_init(ni);
    811 	nssov_host_init(ni);
    812 	nssov_netgroup_init(ni);
    813 	nssov_network_init(ni);
    814 	nssov_passwd_init(ni);
    815 	nssov_protocol_init(ni);
    816 	nssov_rpc_init(ni);
    817 	nssov_service_init(ni);
    818 	nssov_shadow_init(ni);
    819 
    820 	ni->ni_db = be->bd_self;
    821 	ni->ni_pam_opts = NI_PAM_UID2DN;
    822 
    823 	return 0;
    824 }
    825 
    826 static int
    827 nssov_db_destroy(
    828 	BackendDB *be,
    829 	ConfigReply *cr )
    830 {
    831 	return 0;
    832 }
    833 
    834 static int
    835 nssov_db_open(
    836 	BackendDB *be,
    837 	ConfigReply *cr )
    838 {
    839 	slap_overinst *on = (slap_overinst *)be->bd_info;
    840 	nssov_info *ni = on->on_bi.bi_private;
    841 	nssov_mapinfo *mi;
    842 
    843 	int i, sock;
    844 	struct sockaddr_un addr;
    845 
    846 	/* Set default bases */
    847 	for (i=0; i<NM_NONE; i++) {
    848 		if ( BER_BVISNULL( &ni->ni_maps[i].mi_base )) {
    849 			ber_dupbv( &ni->ni_maps[i].mi_base, &be->be_nsuffix[0] );
    850 		}
    851 		if ( ni->ni_maps[i].mi_scope == LDAP_SCOPE_DEFAULT )
    852 			ni->ni_maps[i].mi_scope = LDAP_SCOPE_SUBTREE;
    853 	}
    854 	/* validate attribute maps */
    855 	mi = ni->ni_maps;
    856 	for ( i=0; i<NM_NONE; i++,mi++) {
    857 		const char *text;
    858 		int j;
    859 		for (j=0; !BER_BVISNULL(&mi->mi_attrkeys[j]); j++) {
    860 			/* skip attrs we already validated */
    861 			if ( mi->mi_attrs[j].an_desc ) continue;
    862 			if ( slap_bv2ad( &mi->mi_attrs[j].an_name,
    863 				&mi->mi_attrs[j].an_desc, &text )) {
    864 				Debug(LDAP_DEBUG_ANY,"nssov: invalid attr \"%s\": %s\n",
    865 					mi->mi_attrs[j].an_name.bv_val, text );
    866 				return -1;
    867 			}
    868 		}
    869 		BER_BVZERO(&mi->mi_attrs[j].an_name);
    870 		mi->mi_attrs[j].an_desc = NULL;
    871 	}
    872 
    873 	/* Find host and authorizedService definitions */
    874 	if ((ni->ni_pam_opts & NI_PAM_USERHOST) && !nssov_pam_host_ad)
    875 	{
    876 		const char *text;
    877 		i = slap_str2ad("host", &nssov_pam_host_ad, &text);
    878 		if (i != LDAP_SUCCESS) {
    879 			Debug(LDAP_DEBUG_ANY,"nssov: host attr unknown: %s\n",
    880 				text );
    881 			return -1;
    882 		}
    883 	}
    884 	if ((ni->ni_pam_opts & (NI_PAM_USERSVC|NI_PAM_HOSTSVC)) &&
    885 		!nssov_pam_svc_ad)
    886 	{
    887 		const char *text;
    888 		i = slap_str2ad("authorizedService", &nssov_pam_svc_ad, &text);
    889 		if (i != LDAP_SUCCESS) {
    890 			Debug(LDAP_DEBUG_ANY,"nssov: authorizedService attr unknown: %s\n",
    891 				text );
    892 			return -1;
    893 		}
    894 	}
    895 	if ( slapMode & SLAP_SERVER_MODE ) {
    896 		char ebuf[128];
    897 		/* make sure /var/run/nslcd exists */
    898 		if (mkdir(NSLCD_PATH, (mode_t) 0555)) {
    899 			int saved_errno = errno;
    900 			Debug(LDAP_DEBUG_TRACE,"nssov: mkdir(%s) failed (ignored): %s\n",
    901 					NSLCD_PATH, AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
    902 		} else {
    903 			Debug(LDAP_DEBUG_TRACE,"nssov: created %s\n",NSLCD_PATH );
    904 		}
    905 
    906 		/* create a socket */
    907 		if ( (sock=socket(PF_UNIX,SOCK_STREAM,0))<0 )
    908 		{
    909 			int saved_errno = errno;
    910 			Debug(LDAP_DEBUG_ANY,"nssov: cannot create socket: %s\n",
    911 					AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
    912 			return -1;
    913 		}
    914 		/* remove existing named socket */
    915 		if (unlink(NSLCD_SOCKET)<0)
    916 		{
    917 			int saved_errno = errno;
    918 			Debug( LDAP_DEBUG_TRACE,"nssov: unlink() of "NSLCD_SOCKET" failed (ignored): %s\n",
    919 							AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
    920 		}
    921 		/* create socket address structure */
    922 		memset(&addr,0,sizeof(struct sockaddr_un));
    923 		addr.sun_family=AF_UNIX;
    924 		strncpy(addr.sun_path,NSLCD_SOCKET,sizeof(addr.sun_path));
    925 		addr.sun_path[sizeof(addr.sun_path)-1]='\0';
    926 		/* bind to the named socket */
    927 		if (bind(sock,(struct sockaddr *)&addr,sizeof(struct sockaddr_un)))
    928 		{
    929 			int saved_errno = errno;
    930 			Debug( LDAP_DEBUG_ANY,"nssov: bind() to "NSLCD_SOCKET" failed: %s",
    931 				AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
    932 			if (close(sock)) {
    933 				saved_errno = errno;
    934 				Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",
    935 					AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
    936 			}
    937 			return -1;
    938 		}
    939 		/* close the file descriptor on exit */
    940 		if (fcntl(sock,F_SETFD,FD_CLOEXEC)<0)
    941 		{
    942 			int saved_errno = errno;
    943 			Debug( LDAP_DEBUG_ANY,"nssov: fcntl(F_SETFL,O_NONBLOCK) failed: %s",
    944 				AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
    945 			if (close(sock)) {
    946 				saved_errno = errno;
    947 				Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",
    948 					AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
    949 			}
    950 			return -1;
    951 		}
    952 		/* set permissions of socket so anybody can do requests */
    953 		/* Note: we use chmod() here instead of fchmod() because
    954 			 fchmod does not work on sockets
    955 			 http://www.opengroup.org/onlinepubs/009695399/functions/fchmod.html
    956 			 http://lkml.org/lkml/2005/5/16/11 */
    957 		if (chmod(NSLCD_SOCKET,(mode_t)0666))
    958 		{
    959 			int saved_errno = errno;
    960 			Debug( LDAP_DEBUG_ANY,"nssov: chmod(0666) failed: %s",
    961 				AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
    962 			if (close(sock)) {
    963 				saved_errno = errno;
    964 				Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",
    965 					AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
    966 			}
    967 			return -1;
    968 		}
    969 		/* start listening for connections */
    970 		if (listen(sock,SOMAXCONN)<0)
    971 		{
    972 			int saved_errno = errno;
    973 			Debug( LDAP_DEBUG_ANY,"nssov: listen() failed: %s",
    974 				AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
    975 			if (close(sock)) {
    976 				saved_errno = errno;
    977 				Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",
    978 					AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
    979 			}
    980 			return -1;
    981 		}
    982 		ni->ni_socket = sock;
    983 		ni->ni_conn = connection_client_setup( sock, acceptconn, ni );
    984 	}
    985 
    986 	return 0;
    987 }
    988 
    989 static int
    990 nssov_db_close(
    991 	BackendDB *be,
    992 	ConfigReply *cr )
    993 {
    994 	slap_overinst *on = (slap_overinst *)be->bd_info;
    995 	nssov_info *ni = on->on_bi.bi_private;
    996 
    997 	if ( slapMode & SLAP_SERVER_MODE ) {
    998 		char ebuf[128];
    999 		/* close socket if it's still in use */
   1000 		if (ni->ni_socket >= 0)
   1001 		{
   1002 			if (close(ni->ni_socket)) {
   1003 				int saved_errno = errno;
   1004 				Debug( LDAP_DEBUG_ANY,"problem closing server socket (ignored): %s",
   1005 					AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
   1006 			}
   1007 			ni->ni_socket = -1;
   1008 		}
   1009 		/* remove existing named socket */
   1010 		if (unlink(NSLCD_SOCKET)<0)
   1011 		{
   1012 			int saved_errno = errno;
   1013 			Debug( LDAP_DEBUG_TRACE,"unlink() of "NSLCD_SOCKET" failed (ignored): %s",
   1014 				AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)) );
   1015 		}
   1016 	}
   1017 	return 0;
   1018 }
   1019 
   1020 static slap_overinst nssov;
   1021 
   1022 int
   1023 nssov_initialize( void )
   1024 {
   1025 	int rc;
   1026 
   1027 	nssov.on_bi.bi_type = "nssov";
   1028 	nssov.on_bi.bi_db_init = nssov_db_init;
   1029 	nssov.on_bi.bi_db_destroy = nssov_db_destroy;
   1030 	nssov.on_bi.bi_db_open = nssov_db_open;
   1031 	nssov.on_bi.bi_db_close = nssov_db_close;
   1032 
   1033 	nssov.on_bi.bi_cf_ocs = nssocs;
   1034 
   1035 	rc = config_register_schema( nsscfg, nssocs );
   1036 	if ( rc ) return rc;
   1037 
   1038 	return overlay_register(&nssov);
   1039 }
   1040 
   1041 #if SLAPD_OVER_NSSOV == SLAPD_MOD_DYNAMIC
   1042 int
   1043 init_module( int argc, char *argv[] )
   1044 {
   1045 	return nssov_initialize();
   1046 }
   1047 #endif
   1048