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