1 /* nssov.c - nss-ldap overlay for slapd */
4 * Copyright 2008 by Howard Chu, Symas Corp.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted only as authorized by the OpenLDAP
11 * A copy of this license is available in the file LICENSE in the
12 * top-level directory of the distribution or, alternatively, at
13 * <http://www.OpenLDAP.org/license.html>.
16 * This code references portions of the nss-ldapd package
17 * written by Arthur de Jong. The nss-ldapd code was forked
18 * from the nss-ldap library written by Luke Howard.
23 #ifndef SLAPD_OVER_NSSOV
24 #define SLAPD_OVER_NSSOV SLAPD_MOD_DYNAMIC
27 #include "../slapd/config.h" /* not nss-ldapd config.h */
32 #include <ac/unistd.h>
36 /* buffer sizes for I/O */
37 #define READBUFFER_MINSIZE 32
38 #define READBUFFER_MAXSIZE 64
39 #define WRITEBUFFER_MINSIZE 64
40 #define WRITEBUFFER_MAXSIZE 64*1024
42 /* Find the given attribute's value in the RDN of the DN */
43 int nssov_find_rdnval(struct berval *dn, AttributeDescription *ad, struct berval *value)
51 next = ber_bvchr( &rdn, '+' );
52 if ( rdn.bv_val[ad->ad_cname.bv_len] == '=' &&
53 !ber_bvcmp( &rdn, &ad->ad_cname )) {
55 rdn.bv_len = next - rdn.bv_val;
56 value->bv_val = rdn.bv_val + ad->ad_cname.bv_len + 1;
57 value->bv_len = rdn.bv_len - ad->ad_cname.bv_len - 1;
63 rdn.bv_len -= next - rdn.bv_val;
68 /* create a search filter using a name that requires escaping */
69 int nssov_filter_byname(nssov_mapinfo *mi,int key,struct berval *name,struct berval *buf)
72 struct berval bv2 = {sizeof(buf2),buf2};
74 /* escape attribute */
75 if (nssov_escape(name,&bv2))
78 if (bv2.bv_len + mi->mi_filter.bv_len + mi->mi_attrs[key].an_desc->ad_cname.bv_len + 6 >
81 buf->bv_len = snprintf(buf->bv_val, buf->bv_len, "(&%s(%s=%s))",
82 mi->mi_filter.bv_val, mi->mi_attrs[key].an_desc->ad_cname.bv_val,
87 /* create a search filter using a string converted from an int */
88 int nssov_filter_byid(nssov_mapinfo *mi,int key,struct berval *id,struct berval *buf)
91 if (id->bv_len + mi->mi_filter.bv_len + mi->mi_attrs[key].an_desc->ad_cname.bv_len + 6 >
94 buf->bv_len = snprintf(buf->bv_val, buf->bv_len, "(&%s(%s=%s))",
95 mi->mi_filter.bv_val, mi->mi_attrs[key].an_desc->ad_cname.bv_val,
100 void get_userpassword(struct berval *attr,struct berval *pw)
103 /* go over the entries and return the remainder of the value if it
104 starts with {crypt} or crypt$ */
105 for (i=0;!BER_BVISNULL(&attr[i]);i++)
107 if (strncasecmp(attr[i].bv_val,"{crypt}",7)==0) {
108 pw->bv_val = attr[i].bv_val + 7;
109 pw->bv_len = attr[i].bv_len - 7;
112 if (strncasecmp(attr[i].bv_val,"crypt$",6)==0) {
113 pw->bv_val = attr[i].bv_val + 6;
114 pw->bv_len = attr[i].bv_len - 6;
118 /* just return the first value completely */
120 /* TODO: support more password formats e.g. SMD5
121 (which is $1$ but in a different format)
122 (any code for this is more than welcome) */
125 /* this writes a single address to the stream */
126 int write_address(TFILE *fp,struct berval *addr)
129 struct in_addr ipv4addr;
130 struct in6_addr ipv6addr;
131 /* try to parse the address as IPv4 first, fall back to IPv6 */
132 if (inet_pton(AF_INET,addr->bv_val,&ipv4addr)>0)
134 /* write address type */
135 WRITE_INT32(fp,AF_INET);
136 /* write the address length */
137 WRITE_INT32(fp,sizeof(struct in_addr));
138 /* write the address itself (in network byte order) */
139 WRITE_TYPE(fp,ipv4addr,struct in_addr);
141 else if (inet_pton(AF_INET6,addr->bv_val,&ipv6addr)>0)
143 /* write address type */
144 WRITE_INT32(fp,AF_INET6);
145 /* write the address length */
146 WRITE_INT32(fp,sizeof(struct in6_addr));
147 /* write the address itself (in network byte order) */
148 WRITE_TYPE(fp,ipv6addr,struct in6_addr);
152 /* failure, log but write simple invalid address
153 (otherwise the address list is messed up) */
154 /* TODO: have error message in correct format */
155 Debug(LDAP_DEBUG_ANY,"nssov: unparseable address: %s",addr->bv_val,0,0);
156 /* write an illegal address type */
158 /* write an empty address */
165 int read_address(TFILE *fp,char *addr,int *addrlen,int *af)
169 /* read address family */
171 if ((*af!=AF_INET)&&(*af!=AF_INET6))
173 Debug(LDAP_DEBUG_ANY,"nssov: incorrect address family specified: %d",*af,0,0);
176 /* read address length */
178 if ((len>*addrlen)||(len<=0))
180 Debug(LDAP_DEBUG_ANY,"nssov: address length incorrect: %d",len,0,0);
190 int nssov_escape(struct berval *src,struct berval *dst)
194 /* go over all characters in source string */
195 for (i=0;i<src->bv_len;i++)
197 /* check if char will fit */
198 if (pos>=(dst->bv_len-4))
200 /* do escaping for some characters */
201 switch (src->bv_val[i])
204 strcpy(dst->bv_val+pos,"\\2a");
208 strcpy(dst->bv_val+pos,"\\28");
212 strcpy(dst->bv_val+pos,"\\29");
216 strcpy(dst->bv_val+pos,"\\5c");
220 /* just copy character */
221 dst->bv_val[pos++]=src->bv_val[i];
225 /* terminate destination string */
226 dst->bv_val[pos]='\0';
231 /* read the version information and action from the stream
232 this function returns the read action in location pointer to by action */
233 static int read_header(TFILE *fp,int32_t *action)
236 /* read the protocol version */
237 READ_TYPE(fp,tmpint32,int32_t);
238 if (tmpint32 != (int32_t)NSLCD_VERSION)
240 Debug( LDAP_DEBUG_TRACE,"nssov: wrong nslcd version id (%d)",(int)tmpint32,0,0);
243 /* read the request type */
244 READ(fp,action,sizeof(int32_t));
248 /* read a request message, returns <0 in case of errors,
249 this function closes the socket */
250 static void handleconnection(nssov_info *ni,int sock,Operation *op)
254 struct timeval readtimeout,writetimeout;
257 char authid[sizeof("gidNumber=4294967295+uidNumber=424967295,cn=peercred,cn=external,cn=auth")];
260 if (lutil_getpeereid(sock,&uid,&gid))
261 Debug( LDAP_DEBUG_TRACE,"nssov: connection from unknown client: %s",strerror(errno),0,0);
263 Debug( LDAP_DEBUG_TRACE,"nssov: connection from uid=%d gid=%d",
264 (int)uid,(int)gid,0);
266 /* Should do authid mapping too */
267 op->o_dn.bv_len = sprintf(authid,"gidNumber=%d+uidNumber=%d,cn=peercred,cn=external,cn=auth",
268 (int)uid, (int)gid );
269 op->o_dn.bv_val = authid;
270 op->o_ndn = op->o_dn;
272 /* set the timeouts */
273 readtimeout.tv_sec=0; /* clients should send their request quickly */
274 readtimeout.tv_usec=500000;
275 writetimeout.tv_sec=5; /* clients could be taking some time to process the results */
276 writetimeout.tv_usec=0;
277 /* create a stream object */
278 if ((fp=tio_fdopen(sock,&readtimeout,&writetimeout,
279 READBUFFER_MINSIZE,READBUFFER_MAXSIZE,
280 WRITEBUFFER_MINSIZE,WRITEBUFFER_MAXSIZE))==NULL)
282 Debug( LDAP_DEBUG_ANY,"nssov: cannot create stream for writing: %s",strerror(errno),0,0);
287 if (read_header(fp,&action))
295 case NSLCD_ACTION_ALIAS_BYNAME: (void)nssov_alias_byname(ni,fp,op); break;
296 case NSLCD_ACTION_ALIAS_ALL: (void)nssov_alias_all(ni,fp,op); break;
297 case NSLCD_ACTION_ETHER_BYNAME: (void)nssov_ether_byname(ni,fp,op); break;
298 case NSLCD_ACTION_ETHER_BYETHER: (void)nssov_ether_byether(ni,fp,op); break;
299 case NSLCD_ACTION_ETHER_ALL: (void)nssov_ether_all(ni,fp,op); break;
300 case NSLCD_ACTION_GROUP_BYNAME: (void)nssov_group_byname(ni,fp,op); break;
301 case NSLCD_ACTION_GROUP_BYGID: (void)nssov_group_bygid(ni,fp,op); break;
302 case NSLCD_ACTION_GROUP_BYMEMBER: (void)nssov_group_bymember(ni,fp,op); break;
303 case NSLCD_ACTION_GROUP_ALL: (void)nssov_group_all(ni,fp,op); break;
304 case NSLCD_ACTION_HOST_BYNAME: (void)nssov_host_byname(ni,fp,op); break;
305 case NSLCD_ACTION_HOST_BYADDR: (void)nssov_host_byaddr(ni,fp,op); break;
306 case NSLCD_ACTION_HOST_ALL: (void)nssov_host_all(ni,fp,op); break;
307 case NSLCD_ACTION_NETGROUP_BYNAME: (void)nssov_netgroup_byname(ni,fp,op); break;
308 case NSLCD_ACTION_NETWORK_BYNAME: (void)nssov_network_byname(ni,fp,op); break;
309 case NSLCD_ACTION_NETWORK_BYADDR: (void)nssov_network_byaddr(ni,fp,op); break;
310 case NSLCD_ACTION_NETWORK_ALL: (void)nssov_network_all(ni,fp,op); break;
311 case NSLCD_ACTION_PASSWD_BYNAME: (void)nssov_passwd_byname(ni,fp,op); break;
312 case NSLCD_ACTION_PASSWD_BYUID: (void)nssov_passwd_byuid(ni,fp,op); break;
313 case NSLCD_ACTION_PASSWD_ALL: (void)nssov_passwd_all(ni,fp,op); break;
314 case NSLCD_ACTION_PROTOCOL_BYNAME: (void)nssov_protocol_byname(ni,fp,op); break;
315 case NSLCD_ACTION_PROTOCOL_BYNUMBER:(void)nssov_protocol_bynumber(ni,fp,op); break;
316 case NSLCD_ACTION_PROTOCOL_ALL: (void)nssov_protocol_all(ni,fp,op); break;
317 case NSLCD_ACTION_RPC_BYNAME: (void)nssov_rpc_byname(ni,fp,op); break;
318 case NSLCD_ACTION_RPC_BYNUMBER: (void)nssov_rpc_bynumber(ni,fp,op); break;
319 case NSLCD_ACTION_RPC_ALL: (void)nssov_rpc_all(ni,fp,op); break;
320 case NSLCD_ACTION_SERVICE_BYNAME: (void)nssov_service_byname(ni,fp,op); break;
321 case NSLCD_ACTION_SERVICE_BYNUMBER: (void)nssov_service_bynumber(ni,fp,op); break;
322 case NSLCD_ACTION_SERVICE_ALL: (void)nssov_service_all(ni,fp,op); break;
323 case NSLCD_ACTION_SHADOW_BYNAME: if (uid==0) (void)nssov_shadow_byname(ni,fp,op); break;
324 case NSLCD_ACTION_SHADOW_ALL: if (uid==0) (void)nssov_shadow_all(ni,fp,op); break;
326 Debug( LDAP_DEBUG_ANY,"nssov: invalid request id: %d",(int)action,0,0);
329 /* we're done with the request */
334 /* accept a connection on the socket */
335 static void *acceptconn(void *ctx, void *arg)
337 nssov_info *ni = arg;
338 Connection conn = {0};
339 OperationBuffer opbuf;
343 if ( slapd_shutdown )
347 struct sockaddr_storage addr;
351 /* accept a new connection */
352 alen=(socklen_t)sizeof(struct sockaddr_storage);
353 csock=accept(ni->ni_socket,(struct sockaddr *)&addr,&alen);
354 connection_client_enable(ni->ni_conn);
357 if ((errno==EINTR)||(errno==EAGAIN)||(errno==EWOULDBLOCK))
359 Debug( LDAP_DEBUG_TRACE,"nssov: accept() failed (ignored): %s",strerror(errno),0,0);
362 Debug( LDAP_DEBUG_ANY,"nssov: accept() failed: %s",strerror(errno),0,0);
365 /* make sure O_NONBLOCK is not inherited */
366 if ((j=fcntl(csock,F_GETFL,0))<0)
368 Debug( LDAP_DEBUG_ANY,"nssov: fcntl(F_GETFL) failed: %s",strerror(errno),0,0);
370 Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",strerror(errno),0,0);
373 if (fcntl(csock,F_SETFL,j&~O_NONBLOCK)<0)
375 Debug( LDAP_DEBUG_ANY,"nssov: fcntl(F_SETFL,~O_NONBLOCK) failed: %s",strerror(errno),0,0);
377 Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",strerror(errno),0,0);
381 connection_fake_init( &conn, &opbuf, ctx );
383 op->o_bd = ni->ni_db;
384 op->o_tag = LDAP_REQ_SEARCH;
386 /* handle the connection */
387 handleconnection(ni,csock,op);
390 static slap_verbmasks nss_svcs[] = {
391 { BER_BVC("alias"), NM_alias },
392 { BER_BVC("ether"), NM_ether },
393 { BER_BVC("group"), NM_group },
394 { BER_BVC("host"), NM_host },
395 { BER_BVC("netgroup"), NM_netgroup },
396 { BER_BVC("network"), NM_network },
397 { BER_BVC("passwd"), NM_passwd },
398 { BER_BVC("protocol"), NM_protocol },
399 { BER_BVC("rpc"), NM_rpc },
400 { BER_BVC("service"), NM_service },
401 { BER_BVC("shadow"), NM_shadow },
410 static ConfigDriver nss_cf_gen;
412 static ConfigTable nsscfg[] = {
413 { "nssov-ssd", "service> <url", 3, 3, 0, ARG_MAGIC|NSS_SSD,
414 nss_cf_gen, "(OLcfgCtAt:3.1 NAME 'olcNssSsd' "
415 "DESC 'URL for searches in a given service' "
416 "EQUALITY caseIgnoreMatch "
417 "SYNTAX OMsDirectoryString )", NULL, NULL },
418 { "nssov-map", "service> <orig> <new", 4, 4, 0, ARG_MAGIC|NSS_MAP,
419 nss_cf_gen, "(OLcfgCtAt:3.2 NAME 'olcNssMap' "
420 "DESC 'Map <service> lookups of <orig> attr to <new> attr' "
421 "EQUALITY caseIgnoreMatch "
422 "SYNTAX OMsDirectoryString )", NULL, NULL },
423 { NULL, NULL, 0,0,0, ARG_IGNORED }
426 static ConfigOCs nssocs[] = {
428 "NAME 'olcNssOvConfig' "
429 "DESC 'NSS lookup configuration' "
430 "SUP olcOverlayConfig "
431 "MAY ( olcNssSsd $ olcNssMap ) )",
432 Cft_Overlay, nsscfg },
437 nss_cf_gen(ConfigArgs *c)
439 slap_overinst *on = (slap_overinst *)c->bi;
440 nssov_info *ni = on->on_bi.bi_private;
444 if ( c->op == SLAP_CONFIG_EMIT ) {
448 for (i=NM_alias;i<NM_NONE;i++) {
453 mi = &ni->ni_maps[i];
455 /* ignore all-default services */
456 if ( mi->mi_scope == LDAP_SCOPE_DEFAULT &&
457 bvmatch( &mi->mi_filter, &mi->mi_filter0 ) &&
458 BER_BVISNULL( &mi->mi_base ))
461 if ( BER_BVISNULL( &mi->mi_base ))
462 base = ni->ni_db->be_nsuffix[0];
465 ldap_pvt_scope2bv(mi->mi_scope == LDAP_SCOPE_DEFAULT ?
466 LDAP_SCOPE_SUBTREE : mi->mi_scope, &scope);
467 ssd.bv_len = STRLENOF(" ldap:///???") + nss_svcs[i].word.bv_len +
468 base.bv_len + scope.bv_len + mi->mi_filter.bv_len;
469 ssd.bv_val = ch_malloc( ssd.bv_len + 1 );
470 sprintf(ssd.bv_val, "%s ldap:///%s??%s?%s", nss_svcs[i].word.bv_val,
471 base.bv_val, scope.bv_val, mi->mi_filter.bv_val );
472 ber_bvarray_add( &c->rvalue_vals, &ssd );
478 for (i=NM_alias;i<NM_NONE;i++) {
480 mi = &ni->ni_maps[i];
481 for (j=0;!BER_BVISNULL(&mi->mi_attrkeys[j]);j++) {
482 if ( ber_bvstrcasecmp(&mi->mi_attrkeys[j],
483 &mi->mi_attrs[j].an_name)) {
486 map.bv_len = nss_svcs[i].word.bv_len +
487 mi->mi_attrkeys[j].bv_len +
488 mi->mi_attrs[j].an_desc->ad_cname.bv_len + 2;
489 map.bv_val = ch_malloc(map.bv_len + 1);
490 sprintf(map.bv_val, "%s %s %s", nss_svcs[i].word.bv_val,
491 mi->mi_attrkeys[j].bv_val, mi->mi_attrs[j].an_desc->ad_cname.bv_val );
492 ber_bvarray_add( &c->rvalue_vals, &map );
500 } else if ( c->op == LDAP_MOD_DELETE ) {
507 i = verb_to_mask(c->argv[1], nss_svcs);
511 mi = &ni->ni_maps[i];
512 rc = ldap_url_parse(c->argv[2], &lud);
517 /* Must be LDAP scheme */
518 if (strcasecmp(lud->lud_scheme,"ldap")) {
522 /* Host part, attrs, and extensions must be empty */
523 if (( lud->lud_host && *lud->lud_host ) ||
524 lud->lud_attrs || lud->lud_exts ) {
528 ber_str2bv( lud->lud_dn,0,0,&base);
529 rc = dnNormalize( 0,NULL,NULL,&base,&mi->mi_base,NULL);
532 if ( lud->lud_filter ) {
534 ber_str2bv( lud->lud_filter,0,0,&mi->mi_filter);
535 lud->lud_filter = NULL;
537 mi->mi_scope = lud->lud_scope;
539 ldap_free_urldesc( lud );
543 i = verb_to_mask(c->argv[1], nss_svcs);
547 mi = &ni->ni_maps[i];
548 for (j=0; !BER_BVISNULL(&mi->mi_attrkeys[j]); j++) {
549 if (!strcasecmp(c->argv[2],mi->mi_attrkeys[j].bv_val)) {
550 AttributeDescription *ad = NULL;
552 rc = slap_str2ad( c->argv[3], &ad, &text);
554 mi->mi_attrs[j].an_desc = ad;
555 mi->mi_attrs[j].an_name = ad->ad_cname;
570 slap_overinst *on = (slap_overinst *)be->bd_info;
575 ni = ch_malloc( sizeof(nssov_info) );
576 on->on_bi.bi_private = ni;
578 /* set up map keys */
579 nssov_alias_init(ni);
580 nssov_ether_init(ni);
581 nssov_group_init(ni);
583 nssov_netgroup_init(ni);
584 nssov_network_init(ni);
585 nssov_passwd_init(ni);
586 nssov_protocol_init(ni);
588 nssov_service_init(ni);
589 nssov_shadow_init(ni);
591 ni->ni_db = be->bd_self;
608 slap_overinst *on = (slap_overinst *)be->bd_info;
609 nssov_info *ni = on->on_bi.bi_private;
613 struct sockaddr_un addr;
615 /* Set default bases */
616 for (i=0; i<NM_NONE; i++) {
617 if ( BER_BVISNULL( &ni->ni_maps[i].mi_base )) {
618 ber_dupbv( &ni->ni_maps[i].mi_base, &be->be_nsuffix[0] );
620 if ( ni->ni_maps[i].mi_scope == LDAP_SCOPE_DEFAULT )
621 ni->ni_maps[i].mi_scope = LDAP_SCOPE_SUBTREE;
623 /* validate attribute maps */
625 for ( i=0; i<NM_NONE; i++,mi++) {
628 for (j=0; !BER_BVISNULL(&mi->mi_attrkeys[j]); j++) {
629 /* skip attrs we already validated */
630 if ( mi->mi_attrs[j].an_desc ) continue;
631 if ( slap_bv2ad( &mi->mi_attrs[j].an_name,
632 &mi->mi_attrs[j].an_desc, &text )) {
633 Debug(LDAP_DEBUG_ANY,"nssov: invalid attr \"%s\": %s\n",
634 mi->mi_attrs[j].an_name.bv_val, text, 0 );
638 BER_BVZERO(&mi->mi_attrs[j].an_name);
639 mi->mi_attrs[j].an_desc = NULL;
642 if ( slapMode & SLAP_SERVER_MODE ) {
643 /* create a socket */
644 if ( (sock=socket(PF_UNIX,SOCK_STREAM,0))<0 )
646 Debug(LDAP_DEBUG_ANY,"nssov: cannot create socket: %s",strerror(errno),0,0);
649 /* remove existing named socket */
650 if (unlink(NSLCD_SOCKET)<0)
652 Debug( LDAP_DEBUG_TRACE,"nssov: unlink() of "NSLCD_SOCKET" failed (ignored): %s",
653 strerror(errno),0,0);
655 /* create socket address structure */
656 memset(&addr,0,sizeof(struct sockaddr_un));
657 addr.sun_family=AF_UNIX;
658 strncpy(addr.sun_path,NSLCD_SOCKET,sizeof(addr.sun_path));
659 addr.sun_path[sizeof(addr.sun_path)-1]='\0';
660 /* bind to the named socket */
661 if (bind(sock,(struct sockaddr *)&addr,sizeof(struct sockaddr_un)))
663 Debug( LDAP_DEBUG_ANY,"nssov: bind() to "NSLCD_SOCKET" failed: %s",
664 strerror(errno),0,0);
666 Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",strerror(errno),0,0);
669 /* close the file descriptor on exit */
670 if (fcntl(sock,F_SETFD,FD_CLOEXEC)<0)
672 Debug( LDAP_DEBUG_ANY,"nssov: fcntl(F_SETFL,O_NONBLOCK) failed: %s",strerror(errno),0,0);
674 Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",strerror(errno),0,0);
677 /* set permissions of socket so anybody can do requests */
678 /* Note: we use chmod() here instead of fchmod() because
679 fchmod does not work on sockets
680 http://www.opengroup.org/onlinepubs/009695399/functions/fchmod.html
681 http://lkml.org/lkml/2005/5/16/11 */
682 if (chmod(NSLCD_SOCKET,(mode_t)0666))
684 Debug( LDAP_DEBUG_ANY,"nssov: chmod(0666) failed: %s",strerror(errno),0,0);
686 Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",strerror(errno),0,0);
689 /* start listening for connections */
690 if (listen(sock,SOMAXCONN)<0)
692 Debug( LDAP_DEBUG_ANY,"nssov: listen() failed: %s",strerror(errno),0,0);
694 Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",strerror(errno),0,0);
697 ni->ni_socket = sock;
698 ni->ni_conn = connection_client_setup( sock, acceptconn, ni );
709 slap_overinst *on = (slap_overinst *)be->bd_info;
710 nssov_info *ni = on->on_bi.bi_private;
712 /* close socket if it's still in use */
713 if (ni->ni_socket >= 0);
715 if (close(ni->ni_socket))
716 Debug( LDAP_DEBUG_ANY,"problem closing server socket (ignored): %s",strerror(errno),0,0);
719 /* remove existing named socket */
720 if (unlink(NSLCD_SOCKET)<0)
722 Debug( LDAP_DEBUG_TRACE,"unlink() of "NSLCD_SOCKET" failed (ignored): %s",
723 strerror(errno),0,0);
727 static slap_overinst nssov;
730 nssov_initialize( void )
734 nssov.on_bi.bi_type = "nssov";
735 nssov.on_bi.bi_db_init = nssov_db_init;
736 nssov.on_bi.bi_db_destroy = nssov_db_destroy;
737 nssov.on_bi.bi_db_open = nssov_db_open;
738 nssov.on_bi.bi_db_close = nssov_db_close;
740 nssov.on_bi.bi_cf_ocs = nssocs;
742 rc = config_register_schema( nsscfg, nssocs );
745 return overlay_register(&nssov);
748 #if SLAPD_OVER_NSSOV == SLAPD_MOD_DYNAMIC
750 init_module( int argc, char *argv[] )
752 return nssov_initialize();