1 /* nssov.c - nss-ldap overlay for slapd */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2008-2010 The OpenLDAP Foundation.
6 * Portions Copyright 2008 by Howard Chu, Symas Corp.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted only as authorized by the OpenLDAP
13 * A copy of this license is available in the file LICENSE in the
14 * top-level directory of the distribution or, alternatively, at
15 * <http://www.OpenLDAP.org/license.html>.
18 * This code references portions of the nss-ldapd package
19 * written by Arthur de Jong. The nss-ldapd code was forked
20 * from the nss-ldap library written by Luke Howard.
25 #ifndef SLAPD_OVER_NSSOV
26 #define SLAPD_OVER_NSSOV SLAPD_MOD_DYNAMIC
29 #include "../slapd/config.h" /* not nss-ldapd config.h */
34 #include <ac/unistd.h>
38 AttributeDescription *nssov_pam_host_ad;
39 AttributeDescription *nssov_pam_svc_ad;
41 /* buffer sizes for I/O */
42 #define READBUFFER_MINSIZE 32
43 #define READBUFFER_MAXSIZE 64
44 #define WRITEBUFFER_MINSIZE 64
45 #define WRITEBUFFER_MAXSIZE 64*1024
47 /* Find the given attribute's value in the RDN of the DN */
48 int nssov_find_rdnval(struct berval *dn, AttributeDescription *ad, struct berval *value)
56 next = ber_bvchr( &rdn, '+' );
57 if ( rdn.bv_val[ad->ad_cname.bv_len] == '=' &&
58 !ber_bvcmp( &rdn, &ad->ad_cname )) {
60 rdn.bv_len = next - rdn.bv_val;
61 value->bv_val = rdn.bv_val + ad->ad_cname.bv_len + 1;
62 value->bv_len = rdn.bv_len - ad->ad_cname.bv_len - 1;
68 rdn.bv_len -= next - rdn.bv_val;
73 /* create a search filter using a name that requires escaping */
74 int nssov_filter_byname(nssov_mapinfo *mi,int key,struct berval *name,struct berval *buf)
77 struct berval bv2 = {sizeof(buf2),buf2};
79 /* escape attribute */
80 if (nssov_escape(name,&bv2))
83 if (bv2.bv_len + mi->mi_filter.bv_len + mi->mi_attrs[key].an_desc->ad_cname.bv_len + 6 >
86 buf->bv_len = snprintf(buf->bv_val, buf->bv_len, "(&%s(%s=%s))",
87 mi->mi_filter.bv_val, mi->mi_attrs[key].an_desc->ad_cname.bv_val,
92 /* create a search filter using a string converted from an int */
93 int nssov_filter_byid(nssov_mapinfo *mi,int key,struct berval *id,struct berval *buf)
96 if (id->bv_len + mi->mi_filter.bv_len + mi->mi_attrs[key].an_desc->ad_cname.bv_len + 6 >
99 buf->bv_len = snprintf(buf->bv_val, buf->bv_len, "(&%s(%s=%s))",
100 mi->mi_filter.bv_val, mi->mi_attrs[key].an_desc->ad_cname.bv_val,
105 void get_userpassword(struct berval *attr,struct berval *pw)
108 /* go over the entries and return the remainder of the value if it
109 starts with {crypt} or crypt$ */
110 for (i=0;!BER_BVISNULL(&attr[i]);i++)
112 if (strncasecmp(attr[i].bv_val,"{crypt}",7)==0) {
113 pw->bv_val = attr[i].bv_val + 7;
114 pw->bv_len = attr[i].bv_len - 7;
117 if (strncasecmp(attr[i].bv_val,"crypt$",6)==0) {
118 pw->bv_val = attr[i].bv_val + 6;
119 pw->bv_len = attr[i].bv_len - 6;
123 /* just return the first value completely */
125 /* TODO: support more password formats e.g. SMD5
126 (which is $1$ but in a different format)
127 (any code for this is more than welcome) */
130 /* this writes a single address to the stream */
131 int write_address(TFILE *fp,struct berval *addr)
134 struct in_addr ipv4addr;
135 struct in6_addr ipv6addr;
136 /* try to parse the address as IPv4 first, fall back to IPv6 */
137 if (inet_pton(AF_INET,addr->bv_val,&ipv4addr)>0)
139 /* write address type */
140 WRITE_INT32(fp,AF_INET);
141 /* write the address length */
142 WRITE_INT32(fp,sizeof(struct in_addr));
143 /* write the address itself (in network byte order) */
144 WRITE_TYPE(fp,ipv4addr,struct in_addr);
146 else if (inet_pton(AF_INET6,addr->bv_val,&ipv6addr)>0)
148 /* write address type */
149 WRITE_INT32(fp,AF_INET6);
150 /* write the address length */
151 WRITE_INT32(fp,sizeof(struct in6_addr));
152 /* write the address itself (in network byte order) */
153 WRITE_TYPE(fp,ipv6addr,struct in6_addr);
157 /* failure, log but write simple invalid address
158 (otherwise the address list is messed up) */
159 /* TODO: have error message in correct format */
160 Debug(LDAP_DEBUG_ANY,"nssov: unparseable address: %s\n",addr->bv_val,0,0);
161 /* write an illegal address type */
163 /* write an empty address */
170 int read_address(TFILE *fp,char *addr,int *addrlen,int *af)
174 /* read address family */
176 if ((*af!=AF_INET)&&(*af!=AF_INET6))
178 Debug(LDAP_DEBUG_ANY,"nssov: incorrect address family specified: %d\n",*af,0,0);
181 /* read address length */
183 if ((len>*addrlen)||(len<=0))
185 Debug(LDAP_DEBUG_ANY,"nssov: address length incorrect: %d\n",len,0,0);
195 int nssov_escape(struct berval *src,struct berval *dst)
199 /* go over all characters in source string */
200 for (i=0;i<src->bv_len;i++)
202 /* check if char will fit */
203 if (pos>=(dst->bv_len-4))
205 /* do escaping for some characters */
206 switch (src->bv_val[i])
209 strcpy(dst->bv_val+pos,"\\2a");
213 strcpy(dst->bv_val+pos,"\\28");
217 strcpy(dst->bv_val+pos,"\\29");
221 strcpy(dst->bv_val+pos,"\\5c");
225 /* just copy character */
226 dst->bv_val[pos++]=src->bv_val[i];
230 /* terminate destination string */
231 dst->bv_val[pos]='\0';
236 /* read the version information and action from the stream
237 this function returns the read action in location pointer to by action */
238 static int read_header(TFILE *fp,int32_t *action)
241 /* read the protocol version */
242 READ_TYPE(fp,tmpint32,int32_t);
243 if (tmpint32 != (int32_t)NSLCD_VERSION)
245 Debug( LDAP_DEBUG_TRACE,"nssov: wrong nslcd version id (%d)\n",(int)tmpint32,0,0);
248 /* read the request type */
249 READ(fp,action,sizeof(int32_t));
253 /* read a request message, returns <0 in case of errors,
254 this function closes the socket */
255 static void handleconnection(nssov_info *ni,int sock,Operation *op)
259 struct timeval readtimeout,writetimeout;
262 char authid[sizeof("gidNumber=4294967295+uidNumber=424967295,cn=peercred,cn=external,cn=auth")];
264 struct berval peerbv = { sizeof(peerbuf), peerbuf };
267 if (LUTIL_GETPEEREID(sock,&uid,&gid,&peerbv))
268 Debug( LDAP_DEBUG_TRACE,"nssov: connection from unknown client: %s\n",strerror(errno),0,0);
270 Debug( LDAP_DEBUG_TRACE,"nssov: connection from uid=%d gid=%d\n",
271 (int)uid,(int)gid,0);
273 /* Should do authid mapping too */
274 op->o_dn.bv_len = sprintf(authid,"gidNumber=%d+uidNumber=%d,cn=peercred,cn=external,cn=auth",
275 (int)uid, (int)gid );
276 op->o_dn.bv_val = authid;
277 op->o_ndn = op->o_dn;
279 /* set the timeouts */
280 readtimeout.tv_sec=0; /* clients should send their request quickly */
281 readtimeout.tv_usec=500000;
282 writetimeout.tv_sec=5; /* clients could be taking some time to process the results */
283 writetimeout.tv_usec=0;
284 /* create a stream object */
285 if ((fp=tio_fdopen(sock,&readtimeout,&writetimeout,
286 READBUFFER_MINSIZE,READBUFFER_MAXSIZE,
287 WRITEBUFFER_MINSIZE,WRITEBUFFER_MAXSIZE))==NULL)
289 Debug( LDAP_DEBUG_ANY,"nssov: cannot create stream for writing: %s",strerror(errno),0,0);
294 if (read_header(fp,&action))
302 case NSLCD_ACTION_ALIAS_BYNAME: (void)nssov_alias_byname(ni,fp,op); break;
303 case NSLCD_ACTION_ALIAS_ALL: (void)nssov_alias_all(ni,fp,op); break;
304 case NSLCD_ACTION_ETHER_BYNAME: (void)nssov_ether_byname(ni,fp,op); break;
305 case NSLCD_ACTION_ETHER_BYETHER: (void)nssov_ether_byether(ni,fp,op); break;
306 case NSLCD_ACTION_ETHER_ALL: (void)nssov_ether_all(ni,fp,op); break;
307 case NSLCD_ACTION_GROUP_BYNAME: (void)nssov_group_byname(ni,fp,op); break;
308 case NSLCD_ACTION_GROUP_BYGID: (void)nssov_group_bygid(ni,fp,op); break;
309 case NSLCD_ACTION_GROUP_BYMEMBER: (void)nssov_group_bymember(ni,fp,op); break;
310 case NSLCD_ACTION_GROUP_ALL: (void)nssov_group_all(ni,fp,op); break;
311 case NSLCD_ACTION_HOST_BYNAME: (void)nssov_host_byname(ni,fp,op); break;
312 case NSLCD_ACTION_HOST_BYADDR: (void)nssov_host_byaddr(ni,fp,op); break;
313 case NSLCD_ACTION_HOST_ALL: (void)nssov_host_all(ni,fp,op); break;
314 case NSLCD_ACTION_NETGROUP_BYNAME: (void)nssov_netgroup_byname(ni,fp,op); break;
315 case NSLCD_ACTION_NETWORK_BYNAME: (void)nssov_network_byname(ni,fp,op); break;
316 case NSLCD_ACTION_NETWORK_BYADDR: (void)nssov_network_byaddr(ni,fp,op); break;
317 case NSLCD_ACTION_NETWORK_ALL: (void)nssov_network_all(ni,fp,op); break;
318 case NSLCD_ACTION_PASSWD_BYNAME: (void)nssov_passwd_byname(ni,fp,op); break;
319 case NSLCD_ACTION_PASSWD_BYUID: (void)nssov_passwd_byuid(ni,fp,op); break;
320 case NSLCD_ACTION_PASSWD_ALL: (void)nssov_passwd_all(ni,fp,op); break;
321 case NSLCD_ACTION_PROTOCOL_BYNAME: (void)nssov_protocol_byname(ni,fp,op); break;
322 case NSLCD_ACTION_PROTOCOL_BYNUMBER:(void)nssov_protocol_bynumber(ni,fp,op); break;
323 case NSLCD_ACTION_PROTOCOL_ALL: (void)nssov_protocol_all(ni,fp,op); break;
324 case NSLCD_ACTION_RPC_BYNAME: (void)nssov_rpc_byname(ni,fp,op); break;
325 case NSLCD_ACTION_RPC_BYNUMBER: (void)nssov_rpc_bynumber(ni,fp,op); break;
326 case NSLCD_ACTION_RPC_ALL: (void)nssov_rpc_all(ni,fp,op); break;
327 case NSLCD_ACTION_SERVICE_BYNAME: (void)nssov_service_byname(ni,fp,op); break;
328 case NSLCD_ACTION_SERVICE_BYNUMBER: (void)nssov_service_bynumber(ni,fp,op); break;
329 case NSLCD_ACTION_SERVICE_ALL: (void)nssov_service_all(ni,fp,op); break;
330 case NSLCD_ACTION_SHADOW_BYNAME: if (uid==0) (void)nssov_shadow_byname(ni,fp,op); break;
331 case NSLCD_ACTION_SHADOW_ALL: if (uid==0) (void)nssov_shadow_all(ni,fp,op); break;
332 case NSLCD_ACTION_PAM_AUTHC: (void)pam_authc(ni,fp,op); break;
333 case NSLCD_ACTION_PAM_AUTHZ: (void)pam_authz(ni,fp,op); break;
334 case NSLCD_ACTION_PAM_SESS_O: if (uid==0) (void)pam_sess_o(ni,fp,op); break;
335 case NSLCD_ACTION_PAM_SESS_C: if (uid==0) (void)pam_sess_c(ni,fp,op); break;
336 case NSLCD_ACTION_PAM_PWMOD: (void)pam_pwmod(ni,fp,op); break;
338 Debug( LDAP_DEBUG_ANY,"nssov: invalid request id: %d",(int)action,0,0);
341 /* we're done with the request */
346 /* accept a connection on the socket */
347 static void *acceptconn(void *ctx, void *arg)
349 nssov_info *ni = arg;
350 Connection conn = {0};
351 OperationBuffer opbuf;
355 if ( slapd_shutdown )
359 struct sockaddr_storage addr;
363 /* accept a new connection */
364 alen=(socklen_t)sizeof(struct sockaddr_storage);
365 csock=accept(ni->ni_socket,(struct sockaddr *)&addr,&alen);
366 connection_client_enable(ni->ni_conn);
369 if ((errno==EINTR)||(errno==EAGAIN)||(errno==EWOULDBLOCK))
371 Debug( LDAP_DEBUG_TRACE,"nssov: accept() failed (ignored): %s",strerror(errno),0,0);
374 Debug( LDAP_DEBUG_ANY,"nssov: accept() failed: %s",strerror(errno),0,0);
377 /* make sure O_NONBLOCK is not inherited */
378 if ((j=fcntl(csock,F_GETFL,0))<0)
380 Debug( LDAP_DEBUG_ANY,"nssov: fcntl(F_GETFL) failed: %s",strerror(errno),0,0);
382 Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",strerror(errno),0,0);
385 if (fcntl(csock,F_SETFL,j&~O_NONBLOCK)<0)
387 Debug( LDAP_DEBUG_ANY,"nssov: fcntl(F_SETFL,~O_NONBLOCK) failed: %s",strerror(errno),0,0);
389 Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",strerror(errno),0,0);
393 connection_fake_init( &conn, &opbuf, ctx );
395 conn.c_ssf = conn.c_transport_ssf = local_ssf;
396 op->o_bd = ni->ni_db;
397 op->o_tag = LDAP_REQ_SEARCH;
399 /* handle the connection */
400 handleconnection(ni,csock,op);
403 static slap_verbmasks nss_svcs[] = {
404 { BER_BVC("aliases"), NM_alias },
405 { BER_BVC("ethers"), NM_ether },
406 { BER_BVC("group"), NM_group },
407 { BER_BVC("hosts"), NM_host },
408 { BER_BVC("netgroup"), NM_netgroup },
409 { BER_BVC("networks"), NM_network },
410 { BER_BVC("passwd"), NM_passwd },
411 { BER_BVC("protocols"), NM_protocol },
412 { BER_BVC("rpc"), NM_rpc },
413 { BER_BVC("services"), NM_service },
414 { BER_BVC("shadow"), NM_shadow },
418 static slap_verbmasks pam_opts[] = {
419 { BER_BVC("userhost"), NI_PAM_USERHOST },
420 { BER_BVC("userservice"), NI_PAM_USERSVC },
421 { BER_BVC("usergroup"), NI_PAM_USERGRP },
422 { BER_BVC("hostservice"), NI_PAM_HOSTSVC },
423 { BER_BVC("authz2dn"), NI_PAM_SASL2DN },
424 { BER_BVC("uid2dn"), NI_PAM_UID2DN },
436 static ConfigDriver nss_cf_gen;
438 static ConfigTable nsscfg[] = {
439 { "nssov-ssd", "service> <url", 3, 3, 0, ARG_MAGIC|NSS_SSD,
440 nss_cf_gen, "(OLcfgCtAt:3.1 NAME 'olcNssSsd' "
441 "DESC 'URL for searches in a given service' "
442 "EQUALITY caseIgnoreMatch "
443 "SYNTAX OMsDirectoryString )", NULL, NULL },
444 { "nssov-map", "service> <orig> <new", 4, 4, 0, ARG_MAGIC|NSS_MAP,
445 nss_cf_gen, "(OLcfgCtAt:3.2 NAME 'olcNssMap' "
446 "DESC 'Map <service> lookups of <orig> attr to <new> attr' "
447 "EQUALITY caseIgnoreMatch "
448 "SYNTAX OMsDirectoryString )", NULL, NULL },
449 { "nssov-pam", "options", 2, 0, 0, ARG_MAGIC|NSS_PAM,
450 nss_cf_gen, "(OLcfgCtAt:3.3 NAME 'olcNssPam' "
451 "DESC 'PAM authentication and authorization options' "
452 "EQUALITY caseIgnoreMatch "
453 "SYNTAX OMsDirectoryString )", NULL, NULL },
454 { "nssov-pam-defhost", "hostname", 2, 2, 0, ARG_OFFSET|ARG_BERVAL,
455 (void *)offsetof(struct nssov_info, ni_pam_defhost),
456 "(OLcfgCtAt:3.4 NAME 'olcNssPamDefHost' "
457 "DESC 'Default hostname for service checks' "
458 "EQUALITY caseIgnoreMatch "
459 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
460 { "nssov-pam-group-dn", "DN", 2, 2, 0, ARG_MAGIC|ARG_DN|NSS_PAMGROUP,
461 nss_cf_gen, "(OLcfgCtAt:3.5 NAME 'olcNssPamGroupDN' "
462 "DESC 'DN of group in which membership is required' "
463 "EQUALITY distinguishedNameMatch "
464 "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
465 { "nssov-pam-group-ad", "attr", 2, 2, 0, ARG_OFFSET|ARG_ATDESC,
466 (void *)offsetof(struct nssov_info, ni_pam_group_ad),
467 "(OLcfgCtAt:3.6 NAME 'olcNssPamGroupAD' "
468 "DESC 'Member attribute to use for group check' "
469 "EQUALITY caseIgnoreMatch "
470 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
471 { "nssov-pam-min-uid", "uid", 2, 2, 0, ARG_OFFSET|ARG_INT,
472 (void *)offsetof(struct nssov_info, ni_pam_min_uid),
473 "(OLcfgCtAt:3.7 NAME 'olcNssPamMinUid' "
474 "DESC 'Minimum UID allowed to login' "
475 "EQUALITY integerMatch "
476 "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
477 { "nssov-pam-max-uid", "uid", 2, 2, 0, ARG_OFFSET|ARG_INT,
478 (void *)offsetof(struct nssov_info, ni_pam_max_uid),
479 "(OLcfgCtAt:3.8 NAME 'olcNssPamMaxUid' "
480 "DESC 'Maximum UID allowed to login' "
481 "EQUALITY integerMatch "
482 "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
483 { "nssov-pam-template-ad", "attr", 2, 2, 0, ARG_OFFSET|ARG_ATDESC,
484 (void *)offsetof(struct nssov_info, ni_pam_template_ad),
485 "(OLcfgCtAt:3.9 NAME 'olcNssPamTemplateAD' "
486 "DESC 'Attribute to use for template login name' "
487 "EQUALITY caseIgnoreMatch "
488 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
489 { "nssov-pam-template", "name", 2, 2, 0, ARG_OFFSET|ARG_BERVAL,
490 (void *)offsetof(struct nssov_info, ni_pam_template),
491 "(OLcfgCtAt:3.10 NAME 'olcNssPamTemplate' "
492 "DESC 'Default template login name' "
493 "EQUALITY caseIgnoreMatch "
494 "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
495 { "nssov-pam-session", "service", 2, 2, 0, ARG_MAGIC|ARG_BERVAL|NSS_PAMSESS,
496 nss_cf_gen, "(OLcfgCtAt:3.11 NAME 'olcNssPamSession' "
497 "DESC 'Services for which sessions will be recorded' "
498 "EQUALITY caseIgnoreMatch "
499 "SYNTAX OMsDirectoryString )", NULL, NULL },
500 { NULL, NULL, 0,0,0, ARG_IGNORED }
503 static ConfigOCs nssocs[] = {
505 "NAME 'olcNssOvConfig' "
506 "DESC 'NSS lookup configuration' "
507 "SUP olcOverlayConfig "
508 "MAY ( olcNssSsd $ olcNssMap $ olcNssPam $ olcNssPamDefHost $ "
509 "olcNssPamGroupDN $ olcNssPamGroupAD $ "
510 "olcNssPamMinUid $ olcNssPamMaxUid $ olcNssPamSession $ "
511 "olcNssPamTemplateAD $ olcNssPamTemplate ) )",
512 Cft_Overlay, nsscfg },
517 nss_cf_gen(ConfigArgs *c)
519 slap_overinst *on = (slap_overinst *)c->bi;
520 nssov_info *ni = on->on_bi.bi_private;
525 if ( c->op == SLAP_CONFIG_EMIT ) {
529 for (i=NM_alias;i<NM_NONE;i++) {
534 mi = &ni->ni_maps[i];
536 /* ignore all-default services */
537 if ( mi->mi_scope == LDAP_SCOPE_DEFAULT &&
538 bvmatch( &mi->mi_filter, &mi->mi_filter0 ) &&
539 BER_BVISNULL( &mi->mi_base ))
542 if ( BER_BVISNULL( &mi->mi_base ))
543 base = ni->ni_db->be_nsuffix[0];
546 ldap_pvt_scope2bv(mi->mi_scope == LDAP_SCOPE_DEFAULT ?
547 LDAP_SCOPE_SUBTREE : mi->mi_scope, &scope);
548 ssd.bv_len = STRLENOF(" ldap:///???") + nss_svcs[i].word.bv_len +
549 base.bv_len + scope.bv_len + mi->mi_filter.bv_len;
550 ssd.bv_val = ch_malloc( ssd.bv_len + 1 );
551 sprintf(ssd.bv_val, "%s ldap:///%s??%s?%s", nss_svcs[i].word.bv_val,
552 base.bv_val, scope.bv_val, mi->mi_filter.bv_val );
553 ber_bvarray_add( &c->rvalue_vals, &ssd );
559 for (i=NM_alias;i<NM_NONE;i++) {
561 mi = &ni->ni_maps[i];
562 for (j=0;!BER_BVISNULL(&mi->mi_attrkeys[j]);j++) {
563 if ( ber_bvstrcasecmp(&mi->mi_attrkeys[j],
564 &mi->mi_attrs[j].an_name)) {
567 map.bv_len = nss_svcs[i].word.bv_len +
568 mi->mi_attrkeys[j].bv_len +
569 mi->mi_attrs[j].an_desc->ad_cname.bv_len + 2;
570 map.bv_val = ch_malloc(map.bv_len + 1);
571 sprintf(map.bv_val, "%s %s %s", nss_svcs[i].word.bv_val,
572 mi->mi_attrkeys[j].bv_val, mi->mi_attrs[j].an_desc->ad_cname.bv_val );
573 ber_bvarray_add( &c->rvalue_vals, &map );
580 rc = mask_to_verbs( pam_opts, ni->ni_pam_opts, &c->rvalue_vals );
583 if (!BER_BVISEMPTY( &ni->ni_pam_group_dn )) {
584 value_add_one( &c->rvalue_vals, &ni->ni_pam_group_dn );
585 value_add_one( &c->rvalue_nvals, &ni->ni_pam_group_dn );
591 if (ni->ni_pam_sessions) {
592 ber_bvarray_dup_x( &c->rvalue_vals, ni->ni_pam_sessions, NULL );
599 } else if ( c->op == LDAP_MOD_DELETE ) {
607 i = verb_to_mask(c->argv[1], nss_svcs);
611 mi = &ni->ni_maps[i];
612 rc = ldap_url_parse(c->argv[2], &lud);
617 /* Must be LDAP scheme */
618 if (strcasecmp(lud->lud_scheme,"ldap")) {
622 /* Host part, attrs, and extensions must be empty */
623 if (( lud->lud_host && *lud->lud_host ) ||
624 lud->lud_attrs || lud->lud_exts ) {
628 ber_str2bv( lud->lud_dn,0,0,&base);
629 rc = dnNormalize( 0,NULL,NULL,&base,&mi->mi_base,NULL);
632 if ( lud->lud_filter ) {
634 ber_str2bv( lud->lud_filter,0,0,&mi->mi_filter);
635 lud->lud_filter = NULL;
637 mi->mi_scope = lud->lud_scope;
639 ldap_free_urldesc( lud );
643 i = verb_to_mask(c->argv[1], nss_svcs);
647 mi = &ni->ni_maps[i];
648 for (j=0; !BER_BVISNULL(&mi->mi_attrkeys[j]); j++) {
649 if (!strcasecmp(c->argv[2],mi->mi_attrkeys[j].bv_val)) {
650 AttributeDescription *ad = NULL;
652 rc = slap_str2ad( c->argv[3], &ad, &text);
654 mi->mi_attrs[j].an_desc = ad;
655 mi->mi_attrs[j].an_name = ad->ad_cname;
663 i = verbs_to_mask(c->argc, c->argv, pam_opts, &m);
666 if ((m & NI_PAM_USERHOST) && !nssov_pam_host_ad) {
668 i = slap_str2ad("host", &nssov_pam_host_ad, &text);
669 if (i != LDAP_SUCCESS) {
670 snprintf(c->cr_msg, sizeof(c->cr_msg),
671 "nssov: host attr unknown: %s", text);
672 Debug(LDAP_DEBUG_ANY,"%s\n",c->cr_msg,0,0);
677 if ((m & (NI_PAM_USERSVC|NI_PAM_HOSTSVC)) && !nssov_pam_svc_ad) {
679 i = slap_str2ad("authorizedService", &nssov_pam_svc_ad, &text);
680 if (i != LDAP_SUCCESS) {
681 snprintf(c->cr_msg, sizeof(c->cr_msg),
682 "nssov: authorizedService attr unknown: %s", text);
683 Debug(LDAP_DEBUG_ANY,"%s\n",c->cr_msg,0,0);
693 ni->ni_pam_group_dn = c->value_ndn;
694 ch_free( c->value_dn.bv_val );
697 ber_bvarray_add( &ni->ni_pam_sessions, &c->value_bv );
708 slap_overinst *on = (slap_overinst *)be->bd_info;
713 rc = nssov_pam_init();
716 ni = ch_calloc( 1, sizeof(nssov_info) );
717 on->on_bi.bi_private = ni;
719 /* set up map keys */
720 nssov_alias_init(ni);
721 nssov_ether_init(ni);
722 nssov_group_init(ni);
724 nssov_netgroup_init(ni);
725 nssov_network_init(ni);
726 nssov_passwd_init(ni);
727 nssov_protocol_init(ni);
729 nssov_service_init(ni);
730 nssov_shadow_init(ni);
732 ni->ni_db = be->bd_self;
733 ni->ni_pam_opts = NI_PAM_UID2DN;
750 slap_overinst *on = (slap_overinst *)be->bd_info;
751 nssov_info *ni = on->on_bi.bi_private;
755 struct sockaddr_un addr;
757 /* Set default bases */
758 for (i=0; i<NM_NONE; i++) {
759 if ( BER_BVISNULL( &ni->ni_maps[i].mi_base )) {
760 ber_dupbv( &ni->ni_maps[i].mi_base, &be->be_nsuffix[0] );
762 if ( ni->ni_maps[i].mi_scope == LDAP_SCOPE_DEFAULT )
763 ni->ni_maps[i].mi_scope = LDAP_SCOPE_SUBTREE;
765 /* validate attribute maps */
767 for ( i=0; i<NM_NONE; i++,mi++) {
770 for (j=0; !BER_BVISNULL(&mi->mi_attrkeys[j]); j++) {
771 /* skip attrs we already validated */
772 if ( mi->mi_attrs[j].an_desc ) continue;
773 if ( slap_bv2ad( &mi->mi_attrs[j].an_name,
774 &mi->mi_attrs[j].an_desc, &text )) {
775 Debug(LDAP_DEBUG_ANY,"nssov: invalid attr \"%s\": %s\n",
776 mi->mi_attrs[j].an_name.bv_val, text, 0 );
780 BER_BVZERO(&mi->mi_attrs[j].an_name);
781 mi->mi_attrs[j].an_desc = NULL;
784 /* Find host and authorizedService definitions */
785 if ((ni->ni_pam_opts & NI_PAM_USERHOST) && !nssov_pam_host_ad)
788 i = slap_str2ad("host", &nssov_pam_host_ad, &text);
789 if (i != LDAP_SUCCESS) {
790 Debug(LDAP_DEBUG_ANY,"nssov: host attr unknown: %s\n",
795 if ((ni->ni_pam_opts & (NI_PAM_USERSVC|NI_PAM_HOSTSVC)) &&
799 i = slap_str2ad("authorizedService", &nssov_pam_svc_ad, &text);
800 if (i != LDAP_SUCCESS) {
801 Debug(LDAP_DEBUG_ANY,"nssov: authorizedService attr unknown: %s\n",
806 if ( slapMode & SLAP_SERVER_MODE ) {
807 /* make sure /var/run/nslcd exists */
808 if (mkdir(NSLCD_PATH, (mode_t) 0555)) {
809 Debug(LDAP_DEBUG_TRACE,"nssov: mkdir(%s) failed (ignored): %s\n",
810 NSLCD_PATH,strerror(errno),0);
812 Debug(LDAP_DEBUG_TRACE,"nssov: created %s\n",NSLCD_PATH,0,0);
815 /* create a socket */
816 if ( (sock=socket(PF_UNIX,SOCK_STREAM,0))<0 )
818 Debug(LDAP_DEBUG_ANY,"nssov: cannot create socket: %s\n",strerror(errno),0,0);
821 /* remove existing named socket */
822 if (unlink(NSLCD_SOCKET)<0)
824 Debug( LDAP_DEBUG_TRACE,"nssov: unlink() of "NSLCD_SOCKET" failed (ignored): %s\n",
825 strerror(errno),0,0);
827 /* create socket address structure */
828 memset(&addr,0,sizeof(struct sockaddr_un));
829 addr.sun_family=AF_UNIX;
830 strncpy(addr.sun_path,NSLCD_SOCKET,sizeof(addr.sun_path));
831 addr.sun_path[sizeof(addr.sun_path)-1]='\0';
832 /* bind to the named socket */
833 if (bind(sock,(struct sockaddr *)&addr,sizeof(struct sockaddr_un)))
835 Debug( LDAP_DEBUG_ANY,"nssov: bind() to "NSLCD_SOCKET" failed: %s",
836 strerror(errno),0,0);
838 Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",strerror(errno),0,0);
841 /* close the file descriptor on exit */
842 if (fcntl(sock,F_SETFD,FD_CLOEXEC)<0)
844 Debug( LDAP_DEBUG_ANY,"nssov: fcntl(F_SETFL,O_NONBLOCK) failed: %s",strerror(errno),0,0);
846 Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",strerror(errno),0,0);
849 /* set permissions of socket so anybody can do requests */
850 /* Note: we use chmod() here instead of fchmod() because
851 fchmod does not work on sockets
852 http://www.opengroup.org/onlinepubs/009695399/functions/fchmod.html
853 http://lkml.org/lkml/2005/5/16/11 */
854 if (chmod(NSLCD_SOCKET,(mode_t)0666))
856 Debug( LDAP_DEBUG_ANY,"nssov: chmod(0666) failed: %s",strerror(errno),0,0);
858 Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",strerror(errno),0,0);
861 /* start listening for connections */
862 if (listen(sock,SOMAXCONN)<0)
864 Debug( LDAP_DEBUG_ANY,"nssov: listen() failed: %s",strerror(errno),0,0);
866 Debug( LDAP_DEBUG_ANY,"nssov: problem closing socket: %s",strerror(errno),0,0);
869 ni->ni_socket = sock;
870 ni->ni_conn = connection_client_setup( sock, acceptconn, ni );
881 slap_overinst *on = (slap_overinst *)be->bd_info;
882 nssov_info *ni = on->on_bi.bi_private;
884 if ( slapMode & SLAP_SERVER_MODE ) {
885 /* close socket if it's still in use */
886 if (ni->ni_socket >= 0);
888 if (close(ni->ni_socket))
889 Debug( LDAP_DEBUG_ANY,"problem closing server socket (ignored): %s",strerror(errno),0,0);
892 /* remove existing named socket */
893 if (unlink(NSLCD_SOCKET)<0)
895 Debug( LDAP_DEBUG_TRACE,"unlink() of "NSLCD_SOCKET" failed (ignored): %s",
896 strerror(errno),0,0);
901 static slap_overinst nssov;
904 nssov_initialize( void )
908 nssov.on_bi.bi_type = "nssov";
909 nssov.on_bi.bi_db_init = nssov_db_init;
910 nssov.on_bi.bi_db_destroy = nssov_db_destroy;
911 nssov.on_bi.bi_db_open = nssov_db_open;
912 nssov.on_bi.bi_db_close = nssov_db_close;
914 nssov.on_bi.bi_cf_ocs = nssocs;
916 rc = config_register_schema( nsscfg, nssocs );
919 return overlay_register(&nssov);
922 #if SLAPD_OVER_NSSOV == SLAPD_MOD_DYNAMIC
924 init_module( int argc, char *argv[] )
926 return nssov_initialize();