From 5526f82eb6cb602669b230211eb2266be5ecc784 Mon Sep 17 00:00:00 2001 From: Quanah Gibson-Mount Date: Wed, 3 Jun 2009 22:46:54 +0000 Subject: [PATCH] Sync up nssov --- contrib/slapd-modules/nssov/Makefile | 2 +- contrib/slapd-modules/nssov/README | 52 +- contrib/slapd-modules/nssov/alias.c | 6 +- contrib/slapd-modules/nssov/ether.c | 10 +- contrib/slapd-modules/nssov/group.c | 26 +- contrib/slapd-modules/nssov/host.c | 12 +- contrib/slapd-modules/nssov/ldapns.schema | 25 + contrib/slapd-modules/nssov/netgroup.c | 12 +- contrib/slapd-modules/nssov/network.c | 12 +- contrib/slapd-modules/nssov/nss-ldapd/nslcd.h | 21 + .../nssov/nss-ldapd/nss/Makefile.am | 4 +- .../nssov/nss-ldapd/nss/Makefile.in | 7 +- .../nssov/nss-ldapd/nss/exports.linux | 8 + .../slapd-modules/nssov/nss-ldapd/nss/pam.c | 720 ++++++++++++++++++ contrib/slapd-modules/nssov/nssov.c | 194 ++++- contrib/slapd-modules/nssov/nssov.h | 40 +- contrib/slapd-modules/nssov/pam.c | 668 ++++++++++++++++ contrib/slapd-modules/nssov/passwd.c | 38 +- contrib/slapd-modules/nssov/protocol.c | 14 +- contrib/slapd-modules/nssov/rpc.c | 14 +- contrib/slapd-modules/nssov/service.c | 16 +- contrib/slapd-modules/nssov/shadow.c | 16 +- contrib/slapd-modules/nssov/slapo-nssov.5 | 299 ++++++++ 23 files changed, 2105 insertions(+), 111 deletions(-) create mode 100644 contrib/slapd-modules/nssov/ldapns.schema create mode 100644 contrib/slapd-modules/nssov/nss-ldapd/nss/pam.c create mode 100644 contrib/slapd-modules/nssov/pam.c create mode 100644 contrib/slapd-modules/nssov/slapo-nssov.5 diff --git a/contrib/slapd-modules/nssov/Makefile b/contrib/slapd-modules/nssov/Makefile index 1d231ef57d..dd21999262 100644 --- a/contrib/slapd-modules/nssov/Makefile +++ b/contrib/slapd-modules/nssov/Makefile @@ -32,7 +32,7 @@ all: nssov.la XOBJS = tio.lo OBJS = alias.lo ether.lo group.lo host.lo netgroup.lo network.lo \ - nssov.lo passwd.lo protocol.lo rpc.lo service.lo shadow.lo + nssov.lo passwd.lo protocol.lo rpc.lo service.lo shadow.lo pam.lo .SUFFIXES: .c .o .lo diff --git a/contrib/slapd-modules/nssov/README b/contrib/slapd-modules/nssov/README index e51c90d4b3..37fcda0fa9 100644 --- a/contrib/slapd-modules/nssov/README +++ b/contrib/slapd-modules/nssov/README @@ -1,4 +1,4 @@ -Copyright 2008 Howard Chu, Symas Corp. All rights reserved. +Copyright 2008-2009 Howard Chu, Symas Corp. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted only as authorized by the OpenLDAP @@ -11,7 +11,8 @@ top-level directory of the distribution or, alternatively, at This directory contains a slapd overlay, nssov, that handles NSS lookup requests through a local Unix Domain socket. It uses the same IPC protocol as Arthur de Jong's nss-ldapd, and a complete -copy of the nss-ldapd source is included here. +copy of the nss-ldapd source is included here. It also handles +PAM requests. To use this code, you will need the client-side stub library from nss-ldapd (which resides in nss-ldapd/nss). You will not need the @@ -38,7 +39,7 @@ use RFC2307bis.) The overlay may be configured with Service Search Descriptors (SSDs) for each NSS service that will be used. SSDs are configured using - nssov-svc + nssov-ssd where the may be one of alias @@ -75,8 +76,51 @@ of the config entry is objectClass: olcOverlayConfig objectClass: olcNssOvConfig olcOverlay: {0}nssov - olcNssSvc: passwd ldap:///ou=users,dc=example,dc=com??one + olcNssSsd: passwd ldap:///ou=users,dc=example,dc=com??one olcNssMap: passwd uid accountName which enables the passwd service, and uses the accountName attribute to fetch what is usually retrieved from the uid attribute. + +PAM authentication, account management, session management, and password +management are supported. + +Authentication is performed using Simple Binds. Since all operations occur +inside the slapd overlay, "fake" connections are used and they are +inherently secure. Two methods of mapping the PAM username to an LDAP DN +are provided: + the mapping can be accomplished using slapd's authz-regexp facility. In +this case, a DN of the form + cn=+uid=,cn=,cn=pam,cn=auth +is fed into the regexp matcher. If a match is produced, the resulting DN +is used. + otherwise, the NSS passwd map is invoked (which means it must already +be configured). + +If no DN is found, the overlay returns PAM_USER_UNKNOWN. If the DN is +found, and Password Policy is supported, then the Bind will use the +Password Policy control and return expiration information to PAM. + +Account management also uses two methods. These methods depend on the +ldapns.schema included with the nssov source. + The first is identical to the method used in PADL's pam_ldap module: +host and authorizedService attributes may be looked up in the user's entry, +and checked to determine access. Also a check may be performed to see if +the user is a member of a particular group. This method is pretty +inflexible and doesn't scale well to large networks of users, hosts, +and services. + The second uses slapd's ACL engine to check if the user has "compare" +privilege on an ipHost object whose name matches the current hostname, and +whose authorizedService attribute matches the current service name. This +method is preferred, since it allows authorization to be centralized in +the ipHost entries instead of scattered across the entire user population. +The ipHost entries must have an authorizedService attribute (e.g. by way +of the authorizedServiceObject auxiliary class) to use this method. + +Session management: the overlay may optionally add a "logged in" attribute +to a user's entry for successful logins, and delete the corresponding +value upon logout. The attribute value is of the form + () + +Password management: the overlay will perform a PasswordModify exop +in the server for the given user. diff --git a/contrib/slapd-modules/nssov/alias.c b/contrib/slapd-modules/nssov/alias.c index 7ff83034ba..35aaa8f71d 100644 --- a/contrib/slapd-modules/nssov/alias.c +++ b/contrib/slapd-modules/nssov/alias.c @@ -58,7 +58,7 @@ static int write_alias(nssov_alias_cbp *cbp,Entry *entry) a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[0].an_desc); if ( !a ) { - Debug(LDAP_DEBUG_ANY,"alias entry %s does not contain %s value", + Debug(LDAP_DEBUG_ANY,"alias entry %s does not contain %s value\n", entry->e_name.bv_val,cbp->mi->mi_attrs[0].an_desc->ad_cname.bv_val,0 ); return 0; } @@ -98,7 +98,7 @@ NSSOV_HANDLE( READ_STRING_BUF2(fp,cbp.buf,sizeof(cbp.buf)); cbp.name.bv_len = tmpint32; cbp.name.bv_val = cbp.buf;, - Debug(LDAP_DEBUG_TRACE,"nssov_alias_byname(%s)",cbp.name.bv_val,0,0);, + Debug(LDAP_DEBUG_TRACE,"nssov_alias_byname(%s)\n",cbp.name.bv_val,0,0);, NSLCD_ACTION_ALIAS_BYNAME, nssov_filter_byname(cbp.mi,0,&cbp.name,&filter) ) @@ -108,7 +108,7 @@ NSSOV_HANDLE( struct berval filter; /* no parameters to read */ BER_BVZERO(&cbp.name);, - Debug(LDAP_DEBUG,"nssov_alias_all()",0,0,0);, + Debug(LDAP_DEBUG,"nssov_alias_all()\n",0,0,0);, NSLCD_ACTION_ALIAS_ALL, (filter=cbp.mi->mi_filter,0) ) diff --git a/contrib/slapd-modules/nssov/ether.c b/contrib/slapd-modules/nssov/ether.c index 3055a2aaa0..9f07bbedd2 100644 --- a/contrib/slapd-modules/nssov/ether.c +++ b/contrib/slapd-modules/nssov/ether.c @@ -74,7 +74,7 @@ static int write_ether(nssov_ether_cbp *cbp,Entry *entry) a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[0].an_desc); if ( !a ) { - Debug(LDAP_DEBUG_ANY,"ether entry %s does not contain %s value", + Debug(LDAP_DEBUG_ANY,"ether entry %s does not contain %s value\n", entry->e_name.bv_val,cbp->mi->mi_attrs[0].an_desc->ad_cname.bv_val,0 ); return 0; } @@ -92,7 +92,7 @@ static int write_ether(nssov_ether_cbp *cbp,Entry *entry) a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[1].an_desc); if ( !a ) { - Debug(LDAP_DEBUG_ANY,"ether entry %s does not contain %s value", + Debug(LDAP_DEBUG_ANY,"ether entry %s does not contain %s value\n", entry->e_name.bv_val,cbp->mi->mi_attrs[1].an_desc->ad_cname.bv_val,0 ); return 0; } @@ -127,7 +127,7 @@ NSSOV_HANDLE( READ_STRING_BUF2(fp,cbp.buf,sizeof(cbp.buf)); cbp.name.bv_len = tmpint32; cbp.name.bv_val = cbp.buf;, - Debug(LDAP_DEBUG_TRACE,"nssov_ether_byname(%s)",cbp.name.bv_val,0,0);, + Debug(LDAP_DEBUG_TRACE,"nssov_ether_byname(%s)\n",cbp.name.bv_val,0,0);, NSLCD_ACTION_ETHER_BYNAME, nssov_filter_byname(cbp.mi,0,&cbp.name,&filter) ) @@ -148,7 +148,7 @@ NSSOV_HANDLE( addr.ether_addr_octet[4], addr.ether_addr_octet[5]); cbp.addr.bv_val = cbp.buf;, - Debug(LDAP_DEBUG_TRACE,"nssov_ether_byether(%s)",cbp.addr.bv_val,0,0);, + Debug(LDAP_DEBUG_TRACE,"nssov_ether_byether(%s)\n",cbp.addr.bv_val,0,0);, NSLCD_ACTION_ETHER_BYETHER, nssov_filter_byid(cbp.mi,1,&cbp.addr,&filter) ) @@ -159,7 +159,7 @@ NSSOV_HANDLE( /* no parameters to read */ BER_BVZERO(&cbp.name); BER_BVZERO(&cbp.addr);, - Debug(LDAP_DEBUG_TRACE,"nssov_ether_all()",0,0,0);, + Debug(LDAP_DEBUG_TRACE,"nssov_ether_all()\n",0,0,0);, NSLCD_ACTION_ETHER_ALL, (filter=cbp.mi->mi_filter,0) ) diff --git a/contrib/slapd-modules/nssov/group.c b/contrib/slapd-modules/nssov/group.c index 4c13acedba..866dcd6a10 100644 --- a/contrib/slapd-modules/nssov/group.c +++ b/contrib/slapd-modules/nssov/group.c @@ -1,7 +1,7 @@ /* group.c - group lookup routines */ /* $OpenLDAP$ */ /* - * Copyright 2008 by Howard Chu, Symas Corp. + * Copyright 2008-2009 by Howard Chu, Symas Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -121,6 +121,10 @@ static int isvalidgroupname(struct berval *name) /* check other characters */ for (i=1;ibv_len;i++) { +#ifndef STRICT_GROUPS + /* allow spaces too */ + if (name->bv_val[i] == ' ') continue; +#endif if ( ! ( (name->bv_val[i]>='A' && name->bv_val[i] <= 'Z') || (name->bv_val[i]>='a' && name->bv_val[i] <= 'z') || (name->bv_val[i]>='0' && name->bv_val[i] <= '9') || @@ -145,7 +149,7 @@ static int write_group(nssov_group_cbp *cbp,Entry *entry) a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[CN_KEY].an_desc); if ( !a ) { - Debug(LDAP_DEBUG_ANY,"group entry %s does not contain %s value", + Debug(LDAP_DEBUG_ANY,"group entry %s does not contain %s value\n", entry->e_name.bv_val, cbp->mi->mi_attrs[CN_KEY].an_desc->ad_cname.bv_val,0); return 0; } @@ -163,7 +167,7 @@ static int write_group(nssov_group_cbp *cbp,Entry *entry) a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[GID_KEY].an_desc); if ( !a ) { - Debug(LDAP_DEBUG_ANY,"group entry %s does not contain %s value", + Debug(LDAP_DEBUG_ANY,"group entry %s does not contain %s value\n", entry->e_name.bv_val, cbp->mi->mi_attrs[GID_KEY].an_desc->ad_cname.bv_val,0); return 0; } @@ -225,7 +229,7 @@ static int write_group(nssov_group_cbp *cbp,Entry *entry) { if (!isvalidgroupname(&names[i])) { - Debug(LDAP_DEBUG_ANY,"nssov: group entry %s contains invalid group name: \"%s\"", + Debug(LDAP_DEBUG_ANY,"nssov: group entry %s contains invalid group name: \"%s\"\n", entry->e_name.bv_val,names[i].bv_val,0); } else @@ -237,7 +241,7 @@ static int write_group(nssov_group_cbp *cbp,Entry *entry) gid_t gid; gid = strtol(gids[j].bv_val, &tmp, 0); if ( *tmp ) { - Debug(LDAP_DEBUG_ANY,"nssov: group entry %s contains non-numeric %s value: \"%s\"", + Debug(LDAP_DEBUG_ANY,"nssov: group entry %s contains non-numeric %s value: \"%s\"\n", entry->e_name.bv_val, cbp->mi->mi_attrs[GID_KEY].an_desc->ad_cname.bv_val, names[i].bv_val); continue; @@ -275,14 +279,14 @@ NSSOV_HANDLE( cbp.name.bv_len = tmpint32; cbp.name.bv_val = cbp.buf; if (!isvalidgroupname(&cbp.name)) { - Debug(LDAP_DEBUG_ANY,"nssov_group_byname(%s): invalid group name",cbp.name.bv_val,0,0); + Debug(LDAP_DEBUG_ANY,"nssov_group_byname(%s): invalid group name\n",cbp.name.bv_val,0,0); return -1; } cbp.wantmembers = 1; cbp.ni = ni; BER_BVZERO(&cbp.gidnum); BER_BVZERO(&cbp.user);, - Debug(LDAP_DEBUG_TRACE,"nslcd_group_byname(%s)",cbp.name.bv_val,0,0);, + Debug(LDAP_DEBUG_TRACE,"nslcd_group_byname(%s)\n",cbp.name.bv_val,0,0);, NSLCD_ACTION_GROUP_BYNAME, nssov_filter_byname(cbp.mi,CN_KEY,&cbp.name,&filter) ) @@ -300,7 +304,7 @@ NSSOV_HANDLE( cbp.ni = ni; BER_BVZERO(&cbp.name); BER_BVZERO(&cbp.user);, - Debug(LDAP_DEBUG_TRACE,"nssov_group_bygid(%s)",cbp.gidnum.bv_val,0,0);, + Debug(LDAP_DEBUG_TRACE,"nssov_group_bygid(%s)\n",cbp.gidnum.bv_val,0,0);, NSLCD_ACTION_GROUP_BYGID, nssov_filter_byid(cbp.mi,GID_KEY,&cbp.gidnum,&filter) ) @@ -314,14 +318,14 @@ NSSOV_HANDLE( cbp.user.bv_len = tmpint32; cbp.user.bv_val = cbp.buf; if (!isvalidusername(&cbp.user)) { - Debug(LDAP_DEBUG_ANY,"nssov_group_bymember(%s): invalid user name",cbp.user.bv_val,0,0); + Debug(LDAP_DEBUG_ANY,"nssov_group_bymember(%s): invalid user name\n",cbp.user.bv_val,0,0); return -1; } cbp.wantmembers = 0; cbp.ni = ni; BER_BVZERO(&cbp.name); BER_BVZERO(&cbp.gidnum);, - Debug(LDAP_DEBUG_TRACE,"nssov_group_bymember(%s)",cbp.user.bv_val,0,0);, + Debug(LDAP_DEBUG_TRACE,"nssov_group_bymember(%s)\n",cbp.user.bv_val,0,0);, NSLCD_ACTION_GROUP_BYMEMBER, mkfilter_group_bymember(&cbp,&filter) ) @@ -334,7 +338,7 @@ NSSOV_HANDLE( cbp.ni = ni; BER_BVZERO(&cbp.name); BER_BVZERO(&cbp.gidnum);, - Debug(LDAP_DEBUG_TRACE,"nssov_group_all()",0,0,0);, + Debug(LDAP_DEBUG_TRACE,"nssov_group_all()\n",0,0,0);, NSLCD_ACTION_GROUP_ALL, (filter=cbp.mi->mi_filter,0) ) diff --git a/contrib/slapd-modules/nssov/host.c b/contrib/slapd-modules/nssov/host.c index 7ccf8247bb..588e28e6e6 100644 --- a/contrib/slapd-modules/nssov/host.c +++ b/contrib/slapd-modules/nssov/host.c @@ -59,7 +59,7 @@ static int write_host(nssov_host_cbp *cbp,Entry *entry) a = attr_find( entry->e_attrs, cbp->mi->mi_attrs[0].an_desc ); if ( !a || !a->a_vals ) { - Debug(LDAP_DEBUG_ANY,"host entry %s does not contain %s value", + Debug(LDAP_DEBUG_ANY,"host entry %s does not contain %s value\n", entry->e_name.bv_val, cbp->mi->mi_attrs[0].an_desc->ad_cname.bv_val, 0 ); return 0; } @@ -82,7 +82,7 @@ static int write_host(nssov_host_cbp *cbp,Entry *entry) a = attr_find( entry->e_attrs, cbp->mi->mi_attrs[1].an_desc ); if ( !a || !a->a_vals ) { - Debug(LDAP_DEBUG_ANY,"host entry %s does not contain %s value", + Debug(LDAP_DEBUG_ANY,"host entry %s does not contain %s value\n", entry->e_name.bv_val, cbp->mi->mi_attrs[1].an_desc->ad_cname.bv_val, 0 ); return 0; } @@ -119,7 +119,7 @@ NSSOV_HANDLE( READ_STRING_BUF2(fp,cbp.buf,sizeof(cbp.buf)); cbp.name.bv_len = tmpint32; cbp.name.bv_val = cbp.buf;, - Debug(LDAP_DEBUG_TRACE,"nssov_host_byname(%s)",cbp.name.bv_val,0,0);, + Debug(LDAP_DEBUG_TRACE,"nssov_host_byname(%s)\n",cbp.name.bv_val,0,0);, NSLCD_ACTION_HOST_BYNAME, nssov_filter_byname(cbp.mi,0,&cbp.name,&filter) ) @@ -137,12 +137,12 @@ NSSOV_HANDLE( /* translate the address to a string */ if (inet_ntop(af,addr,cbp.buf,sizeof(cbp.buf))==NULL) { - Debug(LDAP_DEBUG_ANY,"nssov: unable to convert address to string",0,0,0); + Debug(LDAP_DEBUG_ANY,"nssov: unable to convert address to string\n",0,0,0); return -1; } cbp.addr.bv_val = cbp.buf; cbp.addr.bv_len = strlen(cbp.buf);, - Debug(LDAP_DEBUG_TRACE,"nssov_host_byaddr(%s)",cbp.addr.bv_val,0,0);, + Debug(LDAP_DEBUG_TRACE,"nssov_host_byaddr(%s)\n",cbp.addr.bv_val,0,0);, NSLCD_ACTION_HOST_BYADDR, nssov_filter_byid(cbp.mi,1,&cbp.addr,&filter) ) @@ -153,7 +153,7 @@ NSSOV_HANDLE( /* no parameters to read */ BER_BVZERO(&cbp.name); BER_BVZERO(&cbp.addr);, - Debug(LDAP_DEBUG_TRACE,"nssov_host_all()",0,0,0);, + Debug(LDAP_DEBUG_TRACE,"nssov_host_all()\n",0,0,0);, NSLCD_ACTION_HOST_ALL, (filter=cbp.mi->mi_filter,0) ) diff --git a/contrib/slapd-modules/nssov/ldapns.schema b/contrib/slapd-modules/nssov/ldapns.schema new file mode 100644 index 0000000000..2cf9c0a163 --- /dev/null +++ b/contrib/slapd-modules/nssov/ldapns.schema @@ -0,0 +1,25 @@ +# $OpenLDAP$ +# $Id: ldapns.schema,v 1.3 2003/05/29 12:57:29 lukeh Exp $ +# LDAP Name Service Additional Schema +# http://www.iana.org/assignments/gssapi-service-names + +# +# Not part of the distribution: this is a workaround! +# + +attributetype ( 1.3.6.1.4.1.5322.17.2.1 NAME 'authorizedService' + DESC 'IANA GSS-API authorized service name' + EQUALITY caseIgnoreMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{256} ) + +objectclass ( 1.3.6.1.4.1.5322.17.1.1 NAME 'authorizedServiceObject' + DESC 'Auxiliary object class for adding authorizedService attribute' + SUP top + AUXILIARY + MAY authorizedService ) + +objectclass ( 1.3.6.1.4.1.5322.17.1.2 NAME 'hostObject' + DESC 'Auxiliary object class for adding host attribute' + SUP top + AUXILIARY + MAY host ) diff --git a/contrib/slapd-modules/nssov/netgroup.c b/contrib/slapd-modules/nssov/netgroup.c index 7fe781e37a..b9d95c44c1 100644 --- a/contrib/slapd-modules/nssov/netgroup.c +++ b/contrib/slapd-modules/nssov/netgroup.c @@ -91,7 +91,7 @@ static int write_netgroup_triple(TFILE *fp,const char *triple) /* we should have a bracket now */ if (triple[i]!='(') { - Debug(LDAP_DEBUG_ANY,"write_netgroup_triple(): entry does not begin with '(' (entry skipped)",0,0,0); + Debug(LDAP_DEBUG_ANY,"write_netgroup_triple(): entry does not begin with '(' (entry skipped)\n",0,0,0); return 0; } i++; @@ -101,7 +101,7 @@ static int write_netgroup_triple(TFILE *fp,const char *triple) /* nothing else to do */ ; if (triple[i]!=',') { - Debug(LDAP_DEBUG_ANY,"write_netgroup_triple(): missing ',' (entry skipped)",0,0,0); + Debug(LDAP_DEBUG_ANY,"write_netgroup_triple(): missing ',' (entry skipped)\n",0,0,0); return 0; } hoste=i; @@ -112,7 +112,7 @@ static int write_netgroup_triple(TFILE *fp,const char *triple) /* nothing else to do */ ; if (triple[i]!=',') { - Debug(LDAP_DEBUG_ANY,"write_netgroup_triple(): missing ',' (entry skipped)",0,0,0); + Debug(LDAP_DEBUG_ANY,"write_netgroup_triple(): missing ',' (entry skipped)\n",0,0,0); return 0; } usere=i; @@ -123,7 +123,7 @@ static int write_netgroup_triple(TFILE *fp,const char *triple) /* nothing else to do */ ; if (triple[i]!=')') { - Debug(LDAP_DEBUG_ANY,"write_netgroup_triple(): missing ')' (entry skipped)",0,0,0); + Debug(LDAP_DEBUG_ANY,"write_netgroup_triple(): missing ')' (entry skipped)\n",0,0,0); return 0; } domaine=i; @@ -134,7 +134,7 @@ static int write_netgroup_triple(TFILE *fp,const char *triple) /* if anything is left in the string we have a problem */ if (triple[i]!='\0') { - Debug(LDAP_DEBUG_ANY,"write_netgroup_triple(): string contains trailing data (entry skipped)",0,0,0); + Debug(LDAP_DEBUG_ANY,"write_netgroup_triple(): string contains trailing data (entry skipped)\n",0,0,0); return 0; } /* write strings */ @@ -191,7 +191,7 @@ NSSOV_HANDLE( READ_STRING_BUF2(fp,cbp.buf,sizeof(cbp.buf));, cbp.name.bv_len = tmpint32; cbp.name.bv_val = cbp.buf; - Debug(LDAP_DEBUG_TRACE,"nssov_netgroup_byname(%s)",cbp.name.bv_val,0,0);, + Debug(LDAP_DEBUG_TRACE,"nssov_netgroup_byname(%s)\n",cbp.name.bv_val,0,0);, NSLCD_ACTION_NETGROUP_BYNAME, nssov_filter_byname(cbp.mi,0,&cbp.name,&filter) ) diff --git a/contrib/slapd-modules/nssov/network.c b/contrib/slapd-modules/nssov/network.c index 4a6260179f..efaf8b00ca 100644 --- a/contrib/slapd-modules/nssov/network.c +++ b/contrib/slapd-modules/nssov/network.c @@ -59,7 +59,7 @@ static int write_network(nssov_network_cbp *cbp,Entry *entry) a = attr_find( entry->e_attrs, cbp->mi->mi_attrs[0].an_desc ); if ( !a || !a->a_vals ) { - Debug(LDAP_DEBUG_ANY,"network entry %s does not contain %s value", + Debug(LDAP_DEBUG_ANY,"network entry %s does not contain %s value\n", entry->e_name.bv_val,cbp->mi->mi_attrs[0].an_desc->ad_cname.bv_val,0); return 0; } @@ -82,7 +82,7 @@ static int write_network(nssov_network_cbp *cbp,Entry *entry) a = attr_find( entry->e_attrs, cbp->mi->mi_attrs[1].an_desc ); if ( !a || !a->a_vals ) { - Debug(LDAP_DEBUG_ANY,"network entry %s does not contain %s value", + Debug(LDAP_DEBUG_ANY,"network entry %s does not contain %s value\n", entry->e_name.bv_val, cbp->mi->mi_attrs[1].an_desc->ad_cname.bv_val, 0 ); return 0; } @@ -119,7 +119,7 @@ NSSOV_HANDLE( READ_STRING_BUF2(fp,cbp.buf,sizeof(cbp.buf)); cbp.name.bv_len = tmpint32; cbp.name.bv_val = cbp.buf;, - Debug(LDAP_DEBUG_TRACE,"nssov_network_byname(%s)",cbp.name.bv_val,0,0);, + Debug(LDAP_DEBUG_TRACE,"nssov_network_byname(%s)\n",cbp.name.bv_val,0,0);, NSLCD_ACTION_NETWORK_BYNAME, nssov_filter_byname(cbp.mi,0,&cbp.name,&filter) ) @@ -137,12 +137,12 @@ NSSOV_HANDLE( /* translate the address to a string */ if (inet_ntop(af,addr,cbp.buf,sizeof(cbp.buf))==NULL) { - Debug(LDAP_DEBUG_ANY,"nssov: unable to convert address to string",0,0,0); + Debug(LDAP_DEBUG_ANY,"nssov: unable to convert address to string\n",0,0,0); return -1; } cbp.addr.bv_val = cbp.buf; cbp.addr.bv_len = strlen(cbp.buf);, - Debug(LDAP_DEBUG_TRACE,"nslcd_network_byaddr(%s)",cbp.addr.bv_val,0,0);, + Debug(LDAP_DEBUG_TRACE,"nslcd_network_byaddr(%s)\n",cbp.addr.bv_val,0,0);, NSLCD_ACTION_NETWORK_BYADDR, nssov_filter_byid(cbp.mi,1,&cbp.addr,&filter) ) @@ -153,7 +153,7 @@ NSSOV_HANDLE( /* no parameters to read */ BER_BVZERO(&cbp.name); BER_BVZERO(&cbp.addr);, - Debug(LDAP_DEBUG_TRACE,"nssov_network_all()",0,0,0);, + Debug(LDAP_DEBUG_TRACE,"nssov_network_all()\n",0,0,0);, NSLCD_ACTION_NETWORK_ALL, (filter=cbp.mi->mi_filter,0) ) diff --git a/contrib/slapd-modules/nssov/nss-ldapd/nslcd.h b/contrib/slapd-modules/nssov/nss-ldapd/nslcd.h index 38b0962ffa..7dc94370f6 100644 --- a/contrib/slapd-modules/nssov/nss-ldapd/nslcd.h +++ b/contrib/slapd-modules/nssov/nss-ldapd/nslcd.h @@ -197,8 +197,29 @@ #define NSLCD_ACTION_SHADOW_BYNAME 2001 #define NSLCD_ACTION_SHADOW_ALL 2005 +#define NSLCD_ACTION_PAM_AUTHC 20001 +#define NSLCD_ACTION_PAM_AUTHZ 20002 +#define NSLCD_ACTION_PAM_SESS_O 20003 +#define NSLCD_ACTION_PAM_SESS_C 20004 +#define NSLCD_ACTION_PAM_PWMOD 20005 + /* Request result codes. */ #define NSLCD_RESULT_END 3 /* key was not found */ #define NSLCD_RESULT_SUCCESS 0 /* everything ok */ +/* Partial list of PAM result codes. */ +#define NSLCD_PAM_SUCCESS 0 /* everything ok */ +#define NSLCD_PAM_PERM_DENIED 6 /* Permission denied */ +#define NSLCD_PAM_AUTH_ERR 7 /* Authc failure */ +#define NSLCD_PAM_CRED_INSUFFICIENT 8 /* Cannot access authc data */ +#define NSLCD_PAM_AUTHINFO_UNAVAIL 9 /* Cannot retrieve authc info */ +#define NSLCD_PAM_USER_UNKNOWN 10 /* User not known */ +#define NSLCD_PAM_MAXTRIES 11 /* Retry limit reached */ +#define NSLCD_PAM_NEW_AUTHTOK_REQD 12 /* Password expired */ +#define NSLCD_PAM_ACCT_EXPIRED 13 /* Account expired */ +#define NSLCD_PAM_SESSION_ERR 14 /* Cannot make/remove session record */ +#define NSLCD_PAM_AUTHTOK_DISABLE_AGING 23 /* Password aging disabled */ +#define NSLCD_PAM_IGNORE 25 /* Ignore module */ +#define NSLCD_PAM_ABORT 26 /* Fatal error */ + #endif /* not _NSLCD_H */ diff --git a/contrib/slapd-modules/nssov/nss-ldapd/nss/Makefile.am b/contrib/slapd-modules/nssov/nss-ldapd/nss/Makefile.am index 0167d20dff..36de9ed3ab 100644 --- a/contrib/slapd-modules/nssov/nss-ldapd/nss/Makefile.am +++ b/contrib/slapd-modules/nssov/nss-ldapd/nss/Makefile.am @@ -33,10 +33,10 @@ nss_ldap_so_SOURCES = common.c common.h prototypes.h \ ../compat/attrs.h \ aliases.c ethers.c group.c hosts.c netgroup.c \ networks.c passwd.c protocols.c rpc.c services.c \ - shadow.c + shadow.c pam.c nss_ldap_so_LDFLAGS = -shared -Wl,-soname,$(NSS_LDAP_NSS_VERSIONED) \ -Wl,--version-script,\$(srcdir)/exports.linux -nss_ldap_so_LDADD = @nss_ldap_so_LIBS@ ../common/libtio.a +nss_ldap_so_LDADD = @nss_ldap_so_LIBS@ ../common/libtio.a -lpam EXTRA_DIST = exports.linux diff --git a/contrib/slapd-modules/nssov/nss-ldapd/nss/Makefile.in b/contrib/slapd-modules/nssov/nss-ldapd/nss/Makefile.in index 6ffc23af64..0482c75e43 100644 --- a/contrib/slapd-modules/nssov/nss-ldapd/nss/Makefile.in +++ b/contrib/slapd-modules/nssov/nss-ldapd/nss/Makefile.in @@ -70,7 +70,7 @@ am_nss_ldap_so_OBJECTS = common.$(OBJEXT) aliases.$(OBJEXT) \ ethers.$(OBJEXT) group.$(OBJEXT) hosts.$(OBJEXT) \ netgroup.$(OBJEXT) networks.$(OBJEXT) passwd.$(OBJEXT) \ protocols.$(OBJEXT) rpc.$(OBJEXT) services.$(OBJEXT) \ - shadow.$(OBJEXT) + shadow.$(OBJEXT) pam.$(OBJEXT) nss_ldap_so_OBJECTS = $(am_nss_ldap_so_OBJECTS) nss_ldap_so_DEPENDENCIES = ../common/libtio.a nss_ldap_so_LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ @@ -206,12 +206,12 @@ nss_ldap_so_SOURCES = common.c common.h prototypes.h \ ../compat/attrs.h \ aliases.c ethers.c group.c hosts.c netgroup.c \ networks.c passwd.c protocols.c rpc.c services.c \ - shadow.c + shadow.c pam.c nss_ldap_so_LDFLAGS = -shared -Wl,-soname,$(NSS_LDAP_NSS_VERSIONED) \ -Wl,--version-script,\$(srcdir)/exports.linux -nss_ldap_so_LDADD = @nss_ldap_so_LIBS@ ../common/libtio.a +nss_ldap_so_LDADD = @nss_ldap_so_LIBS@ ../common/libtio.a -lpam EXTRA_DIST = exports.linux all: all-am @@ -266,6 +266,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hosts.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netgroup.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/networks.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pam.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/passwd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protocols.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpc.Po@am__quote@ diff --git a/contrib/slapd-modules/nssov/nss-ldapd/nss/exports.linux b/contrib/slapd-modules/nssov/nss-ldapd/nss/exports.linux index 62c031399f..c7f9b1e6e3 100644 --- a/contrib/slapd-modules/nssov/nss-ldapd/nss/exports.linux +++ b/contrib/slapd-modules/nssov/nss-ldapd/nss/exports.linux @@ -78,6 +78,14 @@ EXPORTED { _nss_ldap_getspent_r; _nss_ldap_endspent; + # pam - pluggable auth + pam_sm_acct_mgmt; + pam_sm_authenticate; + pam_sm_chauthtok; + pam_sm_close_session; + pam_sm_open_session; + pam_sm_setcred; + # everything else should not be exported local: *; diff --git a/contrib/slapd-modules/nssov/nss-ldapd/nss/pam.c b/contrib/slapd-modules/nssov/nss-ldapd/nss/pam.c new file mode 100644 index 0000000000..abeae198e3 --- /dev/null +++ b/contrib/slapd-modules/nssov/nss-ldapd/nss/pam.c @@ -0,0 +1,720 @@ +/* + pam.c - pam module functions + + Copyright (C) 2009 Howard Chu + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA +*/ + +#include "config.h" + +#include +#include +#include +#include + +#include "prototypes.h" +#include "common.h" +#include "compat/attrs.h" + +#ifndef HAVE_PAM_PAM_MODULES_H +#include +#else +#include +#endif + +#define CONST_ARG const + +#define IGNORE_UNKNOWN 1 +#define IGNORE_UNAVAIL 2 + +#define PLD_CTX "PAM_LDAPD_CTX" + +#define NSS2PAM_RC(rc,ignore,ok) \ + switch(rc) { \ + case NSS_STATUS_SUCCESS: \ + rc = ok; break; \ + case NSS_STATUS_UNAVAIL: \ + rc = (ignore & IGNORE_UNAVAIL) ? PAM_IGNORE : PAM_AUTHINFO_UNAVAIL; \ + break; \ + case NSS_STATUS_NOTFOUND: \ + rc = (ignore & IGNORE_UNKNOWN) ? PAM_IGNORE: PAM_USER_UNKNOWN; \ + break; \ + default: \ + rc = PAM_SYSTEM_ERR; break; \ + } + +typedef struct pld_ctx { + char *user; + char *dn; + char *tmpluser; + char *authzmsg; + char *oldpw; + int authok; + int authz; + int sessid; + char buf[1024]; +} pld_ctx; + +static int nslcd2pam_rc(int rc) +{ +#define map(i) case NSLCD_##i : rc = i; break + switch(rc) { + map(PAM_SUCCESS); + map(PAM_PERM_DENIED); + map(PAM_AUTH_ERR); + map(PAM_CRED_INSUFFICIENT); + map(PAM_AUTHINFO_UNAVAIL); + map(PAM_USER_UNKNOWN); + map(PAM_MAXTRIES); + map(PAM_NEW_AUTHTOK_REQD); + map(PAM_ACCT_EXPIRED); + map(PAM_SESSION_ERR); + map(PAM_AUTHTOK_DISABLE_AGING); + map(PAM_IGNORE); + map(PAM_ABORT); + } + return rc; +} + +static void pam_clr_ctx( + pld_ctx *ctx) +{ + if (ctx->user) { + free(ctx->user); + ctx->user = NULL; + } + if (ctx->oldpw) { + memset(ctx->oldpw,0,strlen(ctx->oldpw)); + free(ctx->oldpw); + ctx->oldpw = NULL; + } + ctx->dn = NULL; + ctx->tmpluser = NULL; + ctx->authzmsg = NULL; + ctx->authok = 0; + ctx->authz = 0; +} + +static void pam_del_ctx( + pam_handle_t *pamh, void *data, int err) +{ + pld_ctx *ctx = data; + pam_clr_ctx(ctx); + free(ctx); +} + +static int pam_get_ctx( + pam_handle_t *pamh, const char *user, pld_ctx **pctx) +{ + pld_ctx *ctx = NULL; + int rc; + + if (pam_get_data(pamh, PLD_CTX, (CONST_ARG void **)&ctx) == PAM_SUCCESS) { + if (ctx->user && strcmp(ctx->user, user)) { + pam_clr_ctx(ctx); + } + rc = PAM_SUCCESS; + } + if (!ctx) { + ctx = calloc(1, sizeof(*ctx)); + if (!ctx) + return PAM_BUF_ERR; + rc = pam_set_data(pamh, PLD_CTX, ctx, pam_del_ctx); + if (rc != PAM_SUCCESS) + pam_del_ctx(pamh, ctx, 0); + } + if (rc == PAM_SUCCESS) + *pctx = ctx; + return rc; +} + +static int pam_get_authtok( + pam_handle_t *pamh, int flags, char *prompt1, char *prompt2, char **pwd) +{ + int rc; + char *p; + struct pam_message msg[1], *pmsg[1]; + struct pam_response *resp; + struct pam_conv *conv; + + *pwd = NULL; + + rc = pam_get_item (pamh, PAM_CONV, (CONST_ARG void **) &conv); + if (rc == PAM_SUCCESS) { + pmsg[0] = &msg[0]; + msg[0].msg_style = PAM_PROMPT_ECHO_OFF; + msg[0].msg = prompt1; + resp = NULL; + rc = conv->conv (1, + (CONST_ARG struct pam_message **) pmsg, + &resp, conv->appdata_ptr); + } else { + return rc; + } + + if (resp != NULL) { + if ((flags & PAM_DISALLOW_NULL_AUTHTOK) && resp[0].resp == NULL) + { + free (resp); + return PAM_AUTH_ERR; + } + + p = resp[0].resp; + resp[0].resp = NULL; + free (resp); + } else { + return PAM_CONV_ERR; + } + + if (prompt2) { + msg[0].msg = prompt2; + resp = NULL; + rc = conv->conv (1, + (CONST_ARG struct pam_message **) pmsg, + &resp, conv->appdata_ptr); + if (resp && resp[0].resp && !strcmp(resp[0].resp, p)) + rc = PAM_SUCCESS; + else + rc = PAM_AUTHTOK_RECOVERY_ERR; + if (resp) { + if (resp[0].resp) { + (void) memset(resp[0].resp, 0, strlen(resp[0].resp)); + free(resp[0].resp); + } + free(resp); + } + } + + if (rc == PAM_SUCCESS) + *pwd = p; + else if (p) { + memset(p, 0, strlen(p)); + free(p); + } + + return rc; +} + +static enum nss_status pam_read_authc( + TFILE *fp,pld_ctx *ctx,int *errnop) +{ + char *buffer = ctx->buf, *user; + size_t buflen = sizeof(ctx->buf); + size_t bufptr = 0; + int32_t tmpint32; + + READ_STRING_BUF(fp,user); + READ_STRING_BUF(fp,ctx->dn); + READ_INT32(fp,ctx->authok); + READ_INT32(fp,ctx->authz); + READ_STRING_BUF(fp,ctx->authzmsg); + ctx->authok = nslcd2pam_rc(ctx->authok); + ctx->authz = nslcd2pam_rc(ctx->authz); + return NSS_STATUS_SUCCESS; +} + +static enum nss_status pam_do_authc( + pld_ctx *ctx, const char *user, const char *svc,const char *pwd,int *errnop) +{ + NSS_BYGEN(NSLCD_ACTION_PAM_AUTHC, + WRITE_STRING(fp,user); + WRITE_STRING(fp,"" /* DN */); + WRITE_STRING(fp,svc); + WRITE_STRING(fp,pwd), + pam_read_authc(fp,ctx,errnop)); +} + +#define USE_FIRST 1 +#define TRY_FIRST 2 +#define USE_TOKEN 4 + +int pam_sm_authenticate( + pam_handle_t *pamh, int flags, int argc, const char **argv) +{ + int err, rc; + const char *username, *svc; + char *p = NULL; + int first_pass = 0, ignore_flags = 0; + int i; + pld_ctx *ctx; + + for (i = 0; i < argc; i++) { + if (!strcmp (argv[i], "use_first_pass")) + first_pass |= USE_FIRST; + else if (!strcmp (argv[i], "try_first_pass")) + first_pass |= TRY_FIRST; + else if (!strcmp (argv[i], "ignore_unknown_user")) + ignore_flags |= IGNORE_UNKNOWN; + else if (!strcmp (argv[i], "ignore_authinfo_unavail")) + ignore_flags |= IGNORE_UNAVAIL; + else if (!strcmp (argv[i], "no_warn")) + ; + else if (!strcmp (argv[i], "debug")) + ; + else + syslog (LOG_ERR, "illegal option %s", argv[i]); + } + + rc = pam_get_user (pamh, (CONST_ARG char **) &username, NULL); + if (rc != PAM_SUCCESS) + return rc; + + rc = pam_get_ctx(pamh, username, &ctx); + if (rc != PAM_SUCCESS) + return rc; + + rc = pam_get_item (pamh, PAM_SERVICE, (CONST_ARG void **) &svc); + if (rc != PAM_SUCCESS) + return rc; + + for (i=0;i<2;i++) { + if (!first_pass) { + rc = pam_get_authtok(pamh, flags, i ? "LDAP Password: " : + "Password: ", NULL, &p); + i = 2; + if (rc == PAM_SUCCESS) { + pam_set_item(pamh, PAM_AUTHTOK, p); + memset(p, 0, strlen(p)); + free(p); + } else { + break; + } + } + rc = pam_get_item (pamh, PAM_AUTHTOK, (CONST_ARG void **) &p); + if (rc == PAM_SUCCESS) { + rc = pam_do_authc(ctx, username, svc, p, &err); + NSS2PAM_RC(rc, ignore_flags, ctx->authok); + } + if (rc == PAM_SUCCESS || (first_pass & USE_FIRST)) { + break; + } + first_pass = 0; + } + + if (rc == PAM_SUCCESS) { + ctx->user = strdup(username); + if (ctx->authz == PAM_NEW_AUTHTOK_REQD) + ctx->oldpw = strdup(p); + } + + return rc; +} + +int pam_sm_setcred( + pam_handle_t *pamh, int flags, int argc, const char **argv) +{ + return PAM_SUCCESS; +} + +static int +pam_warn( + struct pam_conv *aconv, const char *message, int style, int no_warn) +{ + struct pam_message msg, *pmsg; + struct pam_response *resp; + + if (no_warn) + return PAM_SUCCESS; + + pmsg = &msg; + + msg.msg_style = style; + msg.msg = (char *) message; + resp = NULL; + + return aconv->conv (1, + (CONST_ARG struct pam_message **) &pmsg, + &resp, aconv->appdata_ptr); +} + +static enum nss_status pam_read_authz( + TFILE *fp,pld_ctx *ctx,int *errnop) +{ + char *buffer = ctx->buf; + size_t buflen = sizeof(ctx->buf); + size_t bufptr = 0; + int32_t tmpint32; + + READ_STRING_BUF(fp,ctx->tmpluser); + READ_STRING_BUF(fp,ctx->dn); + READ_INT32(fp,ctx->authz); + READ_STRING_BUF(fp,ctx->authzmsg); + ctx->authz = nslcd2pam_rc(ctx->authz); + return NSS_STATUS_SUCCESS; +} + +static enum nss_status pam_do_authz( + pld_ctx *ctx, const char *svc, const char *ruser, const char *rhost, + const char *tty, int *errnop) +{ + NSS_BYGEN(NSLCD_ACTION_PAM_AUTHZ, + WRITE_STRING(fp,ctx->user); + WRITE_STRING(fp,ctx->dn); + WRITE_STRING(fp,svc); + WRITE_STRING(fp,ruser); + WRITE_STRING(fp,rhost); + WRITE_STRING(fp,tty), + pam_read_authz(fp,ctx,errnop)); +} + +int pam_sm_acct_mgmt( + pam_handle_t *pamh, int flags, int argc, const char **argv) +{ + int rc, err; + const char *username, *svc, *ruser, *rhost, *tty; + int no_warn = 0, ignore_flags = 0; + int i; + struct pam_conv *appconv; + pld_ctx *ctx = NULL, ctx2; + + for (i = 0; i < argc; i++) + { + if (!strcmp (argv[i], "use_first_pass")) + ; + else if (!strcmp (argv[i], "try_first_pass")) + ; + else if (!strcmp (argv[i], "no_warn")) + no_warn = 1; + else if (!strcmp (argv[i], "ignore_unknown_user")) + ignore_flags |= IGNORE_UNKNOWN; + else if (!strcmp (argv[i], "ignore_authinfo_unavail")) + ignore_flags |= IGNORE_UNAVAIL; + else if (!strcmp (argv[i], "debug")) + ; + else + syslog (LOG_ERR, "illegal option %s", argv[i]); + } + + if (flags & PAM_SILENT) + no_warn = 1; + + rc = pam_get_item (pamh, PAM_CONV, (CONST_ARG void **) &appconv); + if (rc != PAM_SUCCESS) + return rc; + + rc = pam_get_user (pamh, (CONST_ARG char **) &username, NULL); + if (rc != PAM_SUCCESS) + return rc; + + if (username == NULL) + return PAM_USER_UNKNOWN; + + rc = pam_get_ctx(pamh, username, &ctx); + if (rc != PAM_SUCCESS) + return rc; + + rc = pam_get_item (pamh, PAM_SERVICE, (CONST_ARG void **) &svc); + if (rc != PAM_SUCCESS) + return rc; + + rc = pam_get_item (pamh, PAM_RUSER, (CONST_ARG void **) &ruser); + if (rc != PAM_SUCCESS) + return rc; + + rc = pam_get_item (pamh, PAM_RHOST, (CONST_ARG void **) &rhost); + if (rc != PAM_SUCCESS) + return rc; + + rc = pam_get_item (pamh, PAM_TTY, (CONST_ARG void **) &tty); + if (rc != PAM_SUCCESS) + return rc; + + ctx2.dn = ctx->dn; + ctx2.user = ctx->user; + rc = pam_do_authz(&ctx2, svc, ruser, rhost, tty, &err); + NSS2PAM_RC(rc, ignore_flags, PAM_SUCCESS); + if (rc != PAM_SUCCESS) { + if (rc != PAM_IGNORE) + pam_warn(appconv, "LDAP authorization failed", PAM_ERROR_MSG, no_warn); + } else { + if (ctx2.authzmsg && ctx2.authzmsg[0]) + pam_warn(appconv, ctx2.authzmsg, PAM_TEXT_INFO, no_warn); + if (ctx2.authz == PAM_SUCCESS) { + rc = ctx->authz; + if (ctx->authzmsg && ctx->authzmsg[0]) + pam_warn(appconv, ctx->authzmsg, PAM_TEXT_INFO, no_warn); + } + } + if ( rc == PAM_SUCCESS && ctx->tmpluser && ctx->tmpluser[0] ) { + rc = pam_set_item(pamh, PAM_USER, ctx->tmpluser); + } + return rc; +} + +static enum nss_status pam_read_sess( + TFILE *fp,pld_ctx *ctx,int *errnop) +{ + int tmpint32; + READ_INT32(fp,ctx->sessid); + return NSS_STATUS_SUCCESS; +} + +static enum nss_status pam_do_sess( + pam_handle_t *pamh,pld_ctx *ctx,int action,int *errnop) +{ + const char *svc = NULL, *tty = NULL, *rhost = NULL, *ruser = NULL; + + pam_get_item (pamh, PAM_SERVICE, (CONST_ARG void **) &svc); + pam_get_item (pamh, PAM_TTY, (CONST_ARG void **) &tty); + pam_get_item (pamh, PAM_RHOST, (CONST_ARG void **) &rhost); + pam_get_item (pamh, PAM_RUSER, (CONST_ARG void **) &ruser); + + { + NSS_BYGEN(action, + WRITE_STRING(fp,ctx->user); + WRITE_STRING(fp,ctx->dn); + WRITE_STRING(fp,svc); + WRITE_STRING(fp,tty); + WRITE_STRING(fp,rhost); + WRITE_STRING(fp,ruser); + WRITE_INT32(fp,ctx->sessid), + pam_read_sess(fp,ctx,errnop)); + } +} + +static int pam_sm_session( + pam_handle_t *pamh, int flags, int argc, const char **argv, + int action, int *no_warn) +{ + int rc, err; + const char *username; + int ignore_flags = 0; + int i, success = PAM_SUCCESS; + pld_ctx *ctx = NULL; + + for (i = 0; i < argc; i++) + { + if (!strcmp (argv[i], "use_first_pass")) + ; + else if (!strcmp (argv[i], "try_first_pass")) + ; + else if (!strcmp (argv[i], "no_warn")) + *no_warn = 1; + else if (!strcmp (argv[i], "ignore_unknown_user")) + ignore_flags |= IGNORE_UNKNOWN; + else if (!strcmp (argv[i], "ignore_authinfo_unavail")) + ignore_flags |= IGNORE_UNAVAIL; + else if (!strcmp (argv[i], "debug")) + ; + else + syslog (LOG_ERR, "illegal option %s", argv[i]); + } + + if (flags & PAM_SILENT) + *no_warn = 1; + + rc = pam_get_user (pamh, (CONST_ARG char **) &username, NULL); + if (rc != PAM_SUCCESS) + return rc; + + if (username == NULL) + return PAM_USER_UNKNOWN; + + rc = pam_get_ctx(pamh, username, &ctx); + if (rc != PAM_SUCCESS) + return rc; + + rc = pam_do_sess(pamh, ctx, action, &err); + NSS2PAM_RC(rc, ignore_flags, PAM_SUCCESS); + return rc; +} + +int pam_sm_open_session( + pam_handle_t *pamh, int flags, int argc, const char **argv) +{ + int rc, no_warn = 0; + struct pam_conv *appconv; + + rc = pam_get_item (pamh, PAM_CONV, (CONST_ARG void **) &appconv); + if (rc != PAM_SUCCESS) + return rc; + + rc = pam_sm_session(pamh,flags,argc,argv,NSLCD_ACTION_PAM_SESS_O,&no_warn); + if (rc != PAM_SUCCESS && rc != PAM_IGNORE) + pam_warn(appconv, "LDAP open_session failed", PAM_ERROR_MSG, no_warn); + return rc; +} + +int pam_sm_close_session( + pam_handle_t *pamh, int flags, int argc, const char **argv) +{ + int rc, no_warn = 0;; + struct pam_conv *appconv; + + rc = pam_get_item (pamh, PAM_CONV, (CONST_ARG void **) &appconv); + if (rc != PAM_SUCCESS) + return rc; + + rc = pam_sm_session(pamh,flags,argc,argv,NSLCD_ACTION_PAM_SESS_C,&no_warn); + if (rc != PAM_SUCCESS && rc != PAM_IGNORE) + pam_warn(appconv, "LDAP close_session failed", PAM_ERROR_MSG, no_warn); + return rc; +} + +static enum nss_status pam_read_pwmod( + TFILE *fp,pld_ctx *ctx,int *errnop) +{ + char *buffer = ctx->buf, *user; + size_t buflen = sizeof(ctx->buf); + size_t bufptr = 0; + int32_t tmpint32; + + READ_STRING_BUF(fp,user); + READ_STRING_BUF(fp,ctx->dn); + READ_INT32(fp,ctx->authz); + READ_STRING_BUF(fp,ctx->authzmsg); + ctx->authz = nslcd2pam_rc(ctx->authz); + return NSS_STATUS_SUCCESS; +} + +static enum nss_status pam_do_pwmod( + pld_ctx *ctx, const char *user, const char *svc, + const char *oldpw, const char *newpw, int *errnop) +{ + NSS_BYGEN(NSLCD_ACTION_PAM_PWMOD, + WRITE_STRING(fp,user); + WRITE_STRING(fp,ctx->dn); + WRITE_STRING(fp,svc); + WRITE_STRING(fp,oldpw); + WRITE_STRING(fp,newpw), + pam_read_pwmod(fp,ctx,errnop)); +} + +int pam_sm_chauthtok( + pam_handle_t *pamh, int flags, int argc, const char **argv) +{ + int rc, err; + const char *username, *p = NULL, *q = NULL, *svc; + int first_pass = 0, no_warn = 0, ignore_flags = 0; + int i, success = PAM_SUCCESS; + struct pam_conv *appconv; + pld_ctx *ctx = NULL; + + for (i = 0; i < argc; i++) + { + if (!strcmp (argv[i], "use_first_pass")) + first_pass |= USE_FIRST; + else if (!strcmp (argv[i], "try_first_pass")) + first_pass |= TRY_FIRST; + else if (!strcmp (argv[i], "use_authtok")) + first_pass |= USE_TOKEN; + else if (!strcmp (argv[i], "no_warn")) + no_warn = 1; + else if (!strcmp (argv[i], "ignore_unknown_user")) + ignore_flags |= IGNORE_UNKNOWN; + else if (!strcmp (argv[i], "ignore_authinfo_unavail")) + ignore_flags |= IGNORE_UNAVAIL; + else if (!strcmp (argv[i], "debug")) + ; + else + syslog (LOG_ERR, "illegal option %s", argv[i]); + } + + if (flags & PAM_SILENT) + no_warn = 1; + + rc = pam_get_item (pamh, PAM_CONV, (CONST_ARG void **) &appconv); + if (rc != PAM_SUCCESS) + return rc; + + rc = pam_get_user (pamh, (CONST_ARG char **) &username, NULL); + if (rc != PAM_SUCCESS) + return rc; + + if (username == NULL) + return PAM_USER_UNKNOWN; + + rc = pam_get_ctx(pamh, username, &ctx); + if (rc != PAM_SUCCESS) + return rc; + + rc = pam_get_item (pamh, PAM_SERVICE, (CONST_ARG void **) &svc); + if (rc != PAM_SUCCESS) + return rc; + + if (flags & PAM_PRELIM_CHECK) { + if (getuid()) { + if (!first_pass) { + rc = pam_get_authtok(pamh, flags, "(current) LDAP Password: ", + NULL, &p); + if (rc == PAM_SUCCESS) { + pam_set_item(pamh, PAM_OLDAUTHTOK, p); + memset(p, 0, strlen(p)); + free(p); + } + } + rc = pam_get_item(pamh, PAM_OLDAUTHTOK, &p); + if (rc) return rc; + } else { + rc = PAM_SUCCESS; + } + if (!ctx->dn) { + rc = pam_do_pwmod(ctx, username, svc, p, NULL, &err); + NSS2PAM_RC(rc, ignore_flags, PAM_SUCCESS); + } + return rc; + } + + rc = pam_get_item(pamh, PAM_OLDAUTHTOK, &p); + if (rc) return rc; + + if (!p) + p = ctx->oldpw; + + if (first_pass) { + rc = pam_get_item(pamh, PAM_AUTHTOK, &q); + if ((rc != PAM_SUCCESS || !q) && (first_pass & (USE_FIRST|USE_TOKEN))) { + if (rc == PAM_SUCCESS) + rc = PAM_AUTHTOK_RECOVERY_ERR; + return rc; + } + } + if (!q) { + rc = pam_get_authtok(pamh, flags, "Enter new LDAP Password: ", + "Retype new LDAP Password: ", &q); + if (rc == PAM_SUCCESS) { + pam_set_item(pamh, PAM_AUTHTOK, q); + memset(q, 0, strlen(q)); + free(q); + rc = pam_get_item(pamh, PAM_AUTHTOK, &q); + } + if (rc != PAM_SUCCESS) + return rc; + } + rc = pam_do_pwmod(ctx, username, svc, p, q, &err); + p = NULL; q = NULL; + NSS2PAM_RC(rc, ignore_flags, PAM_SUCCESS); + if (rc == PAM_SUCCESS) { + rc = ctx->authz; + if (rc != PAM_SUCCESS) + pam_warn(appconv, ctx->authzmsg, PAM_ERROR_MSG, no_warn); + } else if (rc != PAM_IGNORE) + pam_warn(appconv, "LDAP pwmod failed", PAM_ERROR_MSG, no_warn); + return rc; +} + +#ifdef PAM_STATIC +struct pam_module _modstruct = { + "pam_ldapd", + pam_sm_authenticate, + pam_sm_setcred, + pam_sm_acct_mgmt, + pam_sm_open_session, + pam_sm_close_session, + pam_sm_chauthtok +}; +#endif /* PAM_STATIC */ diff --git a/contrib/slapd-modules/nssov/nssov.c b/contrib/slapd-modules/nssov/nssov.c index 9e4d6fead3..08f318d65e 100644 --- a/contrib/slapd-modules/nssov/nssov.c +++ b/contrib/slapd-modules/nssov/nssov.c @@ -1,7 +1,7 @@ /* nssov.c - nss-ldap overlay for slapd */ /* $OpenLDAP$ */ /* - * Copyright 2008 by Howard Chu, Symas Corp. + * Copyright 2008-2009 by Howard Chu, Symas Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,6 +33,9 @@ #include #include +AttributeDescription *nssov_pam_host_ad; +AttributeDescription *nssov_pam_svc_ad; + /* buffer sizes for I/O */ #define READBUFFER_MINSIZE 32 #define READBUFFER_MAXSIZE 64 @@ -152,7 +155,7 @@ int write_address(TFILE *fp,struct berval *addr) /* failure, log but write simple invalid address (otherwise the address list is messed up) */ /* TODO: have error message in correct format */ - Debug(LDAP_DEBUG_ANY,"nssov: unparseable address: %s",addr->bv_val,0,0); + Debug(LDAP_DEBUG_ANY,"nssov: unparseable address: %s\n",addr->bv_val,0,0); /* write an illegal address type */ WRITE_INT32(fp,-1); /* write an empty address */ @@ -170,14 +173,14 @@ int read_address(TFILE *fp,char *addr,int *addrlen,int *af) READ_INT32(fp,*af); if ((*af!=AF_INET)&&(*af!=AF_INET6)) { - Debug(LDAP_DEBUG_ANY,"nssov: incorrect address family specified: %d",*af,0,0); + Debug(LDAP_DEBUG_ANY,"nssov: incorrect address family specified: %d\n",*af,0,0); return -1; } /* read address length */ READ_INT32(fp,len); if ((len>*addrlen)||(len<=0)) { - Debug(LDAP_DEBUG_ANY,"nssov: address length incorrect: %d",len,0,0); + Debug(LDAP_DEBUG_ANY,"nssov: address length incorrect: %d\n",len,0,0); return -1; } *addrlen=len; @@ -237,7 +240,7 @@ static int read_header(TFILE *fp,int32_t *action) READ_TYPE(fp,tmpint32,int32_t); if (tmpint32 != (int32_t)NSLCD_VERSION) { - Debug( LDAP_DEBUG_TRACE,"nssov: wrong nslcd version id (%d)",(int)tmpint32,0,0); + Debug( LDAP_DEBUG_TRACE,"nssov: wrong nslcd version id (%d)\n",(int)tmpint32,0,0); return -1; } /* read the request type */ @@ -258,9 +261,9 @@ static void handleconnection(nssov_info *ni,int sock,Operation *op) /* log connection */ if (lutil_getpeereid(sock,&uid,&gid)) - Debug( LDAP_DEBUG_TRACE,"nssov: connection from unknown client: %s",strerror(errno),0,0); + Debug( LDAP_DEBUG_TRACE,"nssov: connection from unknown client: %s\n",strerror(errno),0,0); else - Debug( LDAP_DEBUG_TRACE,"nssov: connection from uid=%d gid=%d", + Debug( LDAP_DEBUG_TRACE,"nssov: connection from uid=%d gid=%d\n", (int)uid,(int)gid,0); /* Should do authid mapping too */ @@ -322,6 +325,11 @@ static void handleconnection(nssov_info *ni,int sock,Operation *op) case NSLCD_ACTION_SERVICE_ALL: (void)nssov_service_all(ni,fp,op); break; case NSLCD_ACTION_SHADOW_BYNAME: if (uid==0) (void)nssov_shadow_byname(ni,fp,op); break; case NSLCD_ACTION_SHADOW_ALL: if (uid==0) (void)nssov_shadow_all(ni,fp,op); break; + case NSLCD_ACTION_PAM_AUTHC: (void)pam_authc(ni,fp,op); break; + case NSLCD_ACTION_PAM_AUTHZ: (void)pam_authz(ni,fp,op); break; + case NSLCD_ACTION_PAM_SESS_O: if (uid==0) (void)pam_sess_o(ni,fp,op); break; + case NSLCD_ACTION_PAM_SESS_C: if (uid==0) (void)pam_sess_c(ni,fp,op); break; + case NSLCD_ACTION_PAM_PWMOD: (void)pam_pwmod(ni,fp,op); break; default: Debug( LDAP_DEBUG_ANY,"nssov: invalid request id: %d",(int)action,0,0); break; @@ -380,6 +388,7 @@ static void *acceptconn(void *ctx, void *arg) } connection_fake_init( &conn, &opbuf, ctx ); op=&opbuf.ob_op; + conn.c_ssf = conn.c_transport_ssf = local_ssf; op->o_bd = ni->ni_db; op->o_tag = LDAP_REQ_SEARCH; @@ -402,9 +411,22 @@ static slap_verbmasks nss_svcs[] = { { BER_BVNULL, 0 } }; +static slap_verbmasks pam_opts[] = { + { BER_BVC("userhost"), NI_PAM_USERHOST }, + { BER_BVC("userservice"), NI_PAM_USERSVC }, + { BER_BVC("usergroup"), NI_PAM_USERGRP }, + { BER_BVC("hostservice"), NI_PAM_HOSTSVC }, + { BER_BVC("authz2dn"), NI_PAM_SASL2DN }, + { BER_BVC("uid2dn"), NI_PAM_UID2DN }, + { BER_BVNULL, 0 } +}; + enum { NSS_SSD=1, - NSS_MAP + NSS_MAP, + NSS_PAM, + NSS_PAMGROUP, + NSS_PAMSESS }; static ConfigDriver nss_cf_gen; @@ -420,6 +442,57 @@ static ConfigTable nsscfg[] = { "DESC 'Map lookups of attr to attr' " "EQUALITY caseIgnoreMatch " "SYNTAX OMsDirectoryString )", NULL, NULL }, + { "nssov-pam", "options", 2, 0, 0, ARG_MAGIC|NSS_PAM, + nss_cf_gen, "(OLcfgCtAt:3.3 NAME 'olcNssPam' " + "DESC 'PAM authentication and authorization options' " + "EQUALITY caseIgnoreMatch " + "SYNTAX OMsDirectoryString )", NULL, NULL }, + { "nssov-pam-defhost", "hostname", 2, 2, 0, ARG_OFFSET|ARG_BERVAL, + (void *)offsetof(struct nssov_info, ni_pam_defhost), + "(OLcfgCtAt:3.4 NAME 'olcNssPamDefHost' " + "DESC 'Default hostname for service checks' " + "EQUALITY caseIgnoreMatch " + "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, + { "nssov-pam-group-dn", "DN", 2, 2, 0, ARG_MAGIC|ARG_DN|NSS_PAMGROUP, + nss_cf_gen, "(OLcfgCtAt:3.5 NAME 'olcNssPamGroupDN' " + "DESC 'DN of group in which membership is required' " + "EQUALITY distinguishedNameMatch " + "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL }, + { "nssov-pam-group-ad", "attr", 2, 2, 0, ARG_OFFSET|ARG_ATDESC, + (void *)offsetof(struct nssov_info, ni_pam_group_ad), + "(OLcfgCtAt:3.6 NAME 'olcNssPamGroupAD' " + "DESC 'Member attribute to use for group check' " + "EQUALITY caseIgnoreMatch " + "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, + { "nssov-pam-min-uid", "uid", 2, 2, 0, ARG_OFFSET|ARG_INT, + (void *)offsetof(struct nssov_info, ni_pam_min_uid), + "(OLcfgCtAt:3.7 NAME 'olcNssPamMinUid' " + "DESC 'Minimum UID allowed to login' " + "EQUALITY integerMatch " + "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, + { "nssov-pam-max-uid", "uid", 2, 2, 0, ARG_OFFSET|ARG_INT, + (void *)offsetof(struct nssov_info, ni_pam_max_uid), + "(OLcfgCtAt:3.8 NAME 'olcNssPamMaxUid' " + "DESC 'Maximum UID allowed to login' " + "EQUALITY integerMatch " + "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, + { "nssov-pam-template-ad", "attr", 2, 2, 0, ARG_OFFSET|ARG_ATDESC, + (void *)offsetof(struct nssov_info, ni_pam_template_ad), + "(OLcfgCtAt:3.9 NAME 'olcNssPamTemplateAD' " + "DESC 'Attribute to use for template login name' " + "EQUALITY caseIgnoreMatch " + "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, + { "nssov-pam-template", "name", 2, 2, 0, ARG_OFFSET|ARG_BERVAL, + (void *)offsetof(struct nssov_info, ni_pam_template), + "(OLcfgCtAt:3.10 NAME 'olcNssPamTemplate' " + "DESC 'Default template login name' " + "EQUALITY caseIgnoreMatch " + "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL }, + { "nssov-pam-session", "service", 2, 2, 0, ARG_MAGIC|ARG_BERVAL|NSS_PAMSESS, + nss_cf_gen, "(OLcfgCtAt:3.11 NAME 'olcNssPamSession' " + "DESC 'Services for which sessions will be recorded' " + "EQUALITY caseIgnoreMatch " + "SYNTAX OMsDirectoryString )", NULL, NULL }, { NULL, NULL, 0,0,0, ARG_IGNORED } }; @@ -428,7 +501,10 @@ static ConfigOCs nssocs[] = { "NAME 'olcNssOvConfig' " "DESC 'NSS lookup configuration' " "SUP olcOverlayConfig " - "MAY ( olcNssSsd $ olcNssMap ) )", + "MAY ( olcNssSsd $ olcNssMap $ olcNssPam $ olcNssPamDefHost $ " + "olcNssPamGroupDN $ olcNssPamGroupAD $ " + "olcNssPamMinUid $ olcNssPamMaxUid $ olcNssPamSession $ " + "olcNssPamTemplateAD $ olcNssPamTemplate ) )", Cft_Overlay, nsscfg }, { NULL, 0, NULL } }; @@ -440,6 +516,7 @@ nss_cf_gen(ConfigArgs *c) nssov_info *ni = on->on_bi.bi_private; nssov_mapinfo *mi; int i, j, rc = 0; + slap_mask_t m; if ( c->op == SLAP_CONFIG_EMIT ) { switch(c->type) { @@ -495,9 +572,28 @@ nss_cf_gen(ConfigArgs *c) } } break; + case NSS_PAM: + rc = mask_to_verbs( pam_opts, ni->ni_pam_opts, &c->rvalue_vals ); + break; + case NSS_PAMGROUP: + if (!BER_BVISEMPTY( &ni->ni_pam_group_dn )) { + value_add_one( &c->rvalue_vals, &ni->ni_pam_group_dn ); + value_add_one( &c->rvalue_nvals, &ni->ni_pam_group_dn ); + } else { + rc = 1; + } + break; + case NSS_PAMSESS: + if (ni->ni_pam_sessions) { + ber_bvarray_dup_x( &c->rvalue_vals, ni->ni_pam_sessions, NULL ); + } else { + rc = 1; + } + break; } return rc; } else if ( c->op == LDAP_MOD_DELETE ) { + /* FIXME */ return 1; } switch( c->type ) { @@ -558,6 +654,44 @@ nss_cf_gen(ConfigArgs *c) } } break; + case NSS_PAM: + m = ni->ni_pam_opts; + i = verbs_to_mask(c->argc, c->argv, pam_opts, &m); + if (i == 0) { + ni->ni_pam_opts = m; + if ((m & NI_PAM_USERHOST) && !nssov_pam_host_ad) { + const char *text; + i = slap_str2ad("host", &nssov_pam_host_ad, &text); + if (i != LDAP_SUCCESS) { + snprintf(c->cr_msg, sizeof(c->cr_msg), + "nssov: host attr unknown: %s", text); + Debug(LDAP_DEBUG_ANY,"%s\n",c->cr_msg,0,0); + rc = 1; + break; + } + } + if ((m & (NI_PAM_USERSVC|NI_PAM_HOSTSVC)) && !nssov_pam_svc_ad) { + const char *text; + i = slap_str2ad("authorizedService", &nssov_pam_svc_ad, &text); + if (i != LDAP_SUCCESS) { + snprintf(c->cr_msg, sizeof(c->cr_msg), + "nssov: authorizedService attr unknown: %s", text); + Debug(LDAP_DEBUG_ANY,"%s\n",c->cr_msg,0,0); + rc = 1; + break; + } + } + } else { + rc = 1; + } + break; + case NSS_PAMGROUP: + ni->ni_pam_group_dn = c->value_ndn; + ch_free( c->value_dn.bv_val ); + break; + case NSS_PAMSESS: + ber_bvarray_add( &ni->ni_pam_sessions, &c->value_bv ); + break; } return rc; } @@ -570,9 +704,12 @@ nssov_db_init( slap_overinst *on = (slap_overinst *)be->bd_info; nssov_info *ni; nssov_mapinfo *mi; - int i, j; + int rc; - ni = ch_malloc( sizeof(nssov_info) ); + rc = nssov_pam_init(); + if (rc) return rc; + + ni = ch_calloc( 1, sizeof(nssov_info) ); on->on_bi.bi_private = ni; /* set up map keys */ @@ -589,6 +726,7 @@ nssov_db_init( nssov_shadow_init(ni); ni->ni_db = be->bd_self; + ni->ni_pam_opts = NI_PAM_UID2DN; return 0; } @@ -639,17 +777,47 @@ nssov_db_open( mi->mi_attrs[j].an_desc = NULL; } + /* Find host and authorizedService definitions */ + if ((ni->ni_pam_opts & NI_PAM_USERHOST) && !nssov_pam_host_ad) + { + const char *text; + i = slap_str2ad("host", &nssov_pam_host_ad, &text); + if (i != LDAP_SUCCESS) { + Debug(LDAP_DEBUG_ANY,"nssov: host attr unknown: %s\n", + text, 0, 0 ); + return -1; + } + } + if ((ni->ni_pam_opts & (NI_PAM_USERSVC|NI_PAM_HOSTSVC)) && + !nssov_pam_svc_ad) + { + const char *text; + i = slap_str2ad("authorizedService", &nssov_pam_svc_ad, &text); + if (i != LDAP_SUCCESS) { + Debug(LDAP_DEBUG_ANY,"nssov: authorizedService attr unknown: %s\n", + text, 0, 0 ); + return -1; + } + } if ( slapMode & SLAP_SERVER_MODE ) { + /* make sure /var/run/nslcd exists */ + if (mkdir(NSLCD_PATH, (mode_t) 0555)) { + Debug(LDAP_DEBUG_TRACE,"nssov: mkdir(%s) failed (ignored): %s\n", + NSLCD_PATH,strerror(errno),0); + } else { + Debug(LDAP_DEBUG_TRACE,"nssov: created %s\n",NSLCD_PATH,0,0); + } + /* create a socket */ if ( (sock=socket(PF_UNIX,SOCK_STREAM,0))<0 ) { - Debug(LDAP_DEBUG_ANY,"nssov: cannot create socket: %s",strerror(errno),0,0); + Debug(LDAP_DEBUG_ANY,"nssov: cannot create socket: %s\n",strerror(errno),0,0); return -1; } /* remove existing named socket */ if (unlink(NSLCD_SOCKET)<0) { - Debug( LDAP_DEBUG_TRACE,"nssov: unlink() of "NSLCD_SOCKET" failed (ignored): %s", + Debug( LDAP_DEBUG_TRACE,"nssov: unlink() of "NSLCD_SOCKET" failed (ignored): %s\n", strerror(errno),0,0); } /* create socket address structure */ diff --git a/contrib/slapd-modules/nssov/nssov.h b/contrib/slapd-modules/nssov/nssov.h index 01303ac57d..6e65ce0745 100644 --- a/contrib/slapd-modules/nssov/nssov.h +++ b/contrib/slapd-modules/nssov/nssov.h @@ -9,8 +9,12 @@ #ifndef NSSOV_H #define NSSOV_H +#ifndef NSLCD_PATH +#define NSLCD_PATH "/var/run/nslcd" +#endif + #ifndef NSLCD_SOCKET -#define NSLCD_SOCKET "/var/run/nslcd/socket" +#define NSLCD_SOCKET NSLCD_PATH "/socket" #endif #include @@ -64,8 +68,32 @@ typedef struct nssov_info int ni_socket; Connection *ni_conn; BackendDB *ni_db; + + /* PAM authz support... */ + slap_mask_t ni_pam_opts; + struct berval ni_pam_group_dn; + AttributeDescription *ni_pam_group_ad; + int ni_pam_min_uid; + int ni_pam_max_uid; + AttributeDescription *ni_pam_template_ad; + struct berval ni_pam_template; + struct berval ni_pam_defhost; + struct berval *ni_pam_sessions; } nssov_info; +#define NI_PAM_USERHOST 1 /* old style host checking */ +#define NI_PAM_USERSVC 2 /* old style service checking */ +#define NI_PAM_USERGRP 4 /* old style group checking */ +#define NI_PAM_HOSTSVC 8 /* new style authz checking */ +#define NI_PAM_SASL2DN 0x10 /* use sasl2dn */ +#define NI_PAM_UID2DN 0x20 /* use uid2dn */ + +#define NI_PAM_OLD (NI_PAM_USERHOST|NI_PAM_USERSVC|NI_PAM_USERGRP) +#define NI_PAM_NEW NI_PAM_HOSTSVC + +extern AttributeDescription *nssov_pam_host_ad; +extern AttributeDescription *nssov_pam_svc_ad; + /* Read the default configuration file. */ void nssov_cfg_init(nssov_info *ni,const char *fname); @@ -139,11 +167,12 @@ int read_address(TFILE *fp,char *addr,int *addrlen,int *af); /* checks to see if the specified string is a valid username */ int isvalidusername(struct berval *name); -/* transforms the DN info a uid doing an LDAP lookup if needed */ +/* transforms the DN into a uid doing an LDAP lookup if needed */ int nssov_dn2uid(Operation *op,nssov_info *ni,struct berval *dn,struct berval *uid); /* transforms the uid into a DN by doing an LDAP lookup */ int nssov_uid2dn(Operation *op,nssov_info *ni,struct berval *uid,struct berval *dn); +int nssov_name2dn_cb(Operation *op, SlapReply *rs); /* Escapes characters in a string for use in a search filter. */ int nssov_escape(struct berval *src,struct berval *dst); @@ -163,6 +192,8 @@ void nssov_rpc_init(nssov_info *ni); void nssov_service_init(nssov_info *ni); void nssov_shadow_init(nssov_info *ni); +int nssov_pam_init(void); + /* these are the different functions that handle the database specific actions, see nslcd.h for the action descriptions */ int nssov_alias_byname(nssov_info *ni,TFILE *fp,Operation *op); @@ -195,6 +226,11 @@ int nssov_service_bynumber(nssov_info *ni,TFILE *fp,Operation *op); int nssov_service_all(nssov_info *ni,TFILE *fp,Operation *op); int nssov_shadow_byname(nssov_info *ni,TFILE *fp,Operation *op); int nssov_shadow_all(nssov_info *ni,TFILE *fp,Operation *op); +int pam_authc(nssov_info *ni,TFILE *fp,Operation *op); +int pam_authz(nssov_info *ni,TFILE *fp,Operation *op); +int pam_sess_o(nssov_info *ni,TFILE *fp,Operation *op); +int pam_sess_c(nssov_info *ni,TFILE *fp,Operation *op); +int pam_pwmod(nssov_info *ni,TFILE *fp,Operation *op); /* config initialization */ #define NSSOV_INIT(db) \ diff --git a/contrib/slapd-modules/nssov/pam.c b/contrib/slapd-modules/nssov/pam.c new file mode 100644 index 0000000000..d424999857 --- /dev/null +++ b/contrib/slapd-modules/nssov/pam.c @@ -0,0 +1,668 @@ +/* pam.c - pam processing routines */ +/* $OpenLDAP$ */ +/* + * Copyright 2009 by Howard Chu, Symas Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . + */ + +#include "nssov.h" +#include "lutil.h" + +static int ppolicy_cid; +static AttributeDescription *ad_loginStatus; + +const char *at_loginStatus = + "( 1.3.6.1.4.1.4745.1.20.1 " + "NAME ( 'loginStatus' ) " + "DESC 'Currently logged in sessions for a user' " + "EQUALITY caseIgnoreMatch " + "SUBSTR caseIgnoreSubstringsMatch " + "ORDERING caseIgnoreOrderingMatch " + "SYNTAX OMsDirectoryString " + "USAGE directoryOperation )"; + +struct paminfo { + struct berval uid; + struct berval dn; + struct berval svc; + struct berval pwd; + int authz; + struct berval msg; +}; + +static int pam_bindcb( + Operation *op, SlapReply *rs) +{ + struct paminfo *pi = op->o_callback->sc_private; + LDAPControl *ctrl = ldap_control_find(LDAP_CONTROL_PASSWORDPOLICYRESPONSE, + rs->sr_ctrls, NULL); + if (ctrl) { + LDAP *ld; + ber_int_t expire, grace; + LDAPPasswordPolicyError error; + + ldap_create(&ld); + if (ld) { + int rc = ldap_parse_passwordpolicy_control(ld,ctrl, + &expire,&grace,&error); + if (rc == LDAP_SUCCESS) { + if (expire >= 0) { + char *unit = "seconds"; + if (expire > 60) { + expire /= 60; + unit = "minutes"; + } + if (expire > 60) { + expire /= 60; + unit = "hours"; + } + if (expire > 24) { + expire /= 24; + unit = "days"; + } +#if 0 /* Who warns about expiration so far in advance? */ + if (expire > 7) { + expire /= 7; + unit = "weeks"; + } + if (expire > 4) { + expire /= 4; + unit = "months"; + } + if (expire > 12) { + expire /= 12; + unit = "years"; + } +#endif + pi->msg.bv_len = sprintf(pi->msg.bv_val, + "\nWARNING: Password expires in %d %s\n", expire, unit); + } else if (grace > 0) { + pi->msg.bv_len = sprintf(pi->msg.bv_val, + "Password expired; %d grace logins remaining", + grace); + pi->authz = NSLCD_PAM_NEW_AUTHTOK_REQD; + } else if (error != PP_noError) { + ber_str2bv(ldap_passwordpolicy_err2txt(error), 0, 0, + &pi->msg); + switch (error) { + case PP_passwordExpired: + /* report this during authz */ + rs->sr_err = LDAP_SUCCESS; + /* fallthru */ + case PP_changeAfterReset: + pi->authz = NSLCD_PAM_NEW_AUTHTOK_REQD; + } + } + } + ldap_ld_free(ld,0,NULL,NULL); + } + } + return LDAP_SUCCESS; +} + +int pam_do_bind(nssov_info *ni,TFILE *fp,Operation *op, + struct paminfo *pi) +{ + int rc; + slap_callback cb = {0}; + SlapReply rs = {REP_RESULT}; + struct berval sdn; + + pi->msg.bv_val = pi->pwd.bv_val; + pi->msg.bv_len = 0; + pi->authz = NSLCD_PAM_SUCCESS; + BER_BVZERO(&pi->dn); + + if (!isvalidusername(&pi->uid)) { + Debug(LDAP_DEBUG_ANY,"nssov_pam_do_bind(%s): invalid user name\n", + pi->uid.bv_val,0,0); + rc = NSLCD_PAM_USER_UNKNOWN; + goto finish; + } + + if (ni->ni_pam_opts & NI_PAM_SASL2DN) { + int hlen = global_host_bv.bv_len; + + /* cn=+uid=,cn=,cn=pam,cn=auth */ + sdn.bv_len = pi->uid.bv_len + pi->svc.bv_len + hlen + + STRLENOF( "cn=+uid=,cn=,cn=pam,cn=auth" ); + sdn.bv_val = op->o_tmpalloc( sdn.bv_len + 1, op->o_tmpmemctx ); + sprintf(sdn.bv_val, "cn=%s+uid=%s,cn=%s,cn=pam,cn=auth", + pi->svc.bv_val, pi->uid.bv_val, global_host_bv.bv_val); + slap_sasl2dn(op, &sdn, &pi->dn, 0); + op->o_tmpfree( sdn.bv_val, op->o_tmpmemctx ); + } + + /* If no luck, do a basic uid search */ + if (BER_BVISEMPTY(&pi->dn) && (ni->ni_pam_opts & NI_PAM_UID2DN)) { + nssov_uid2dn(op, ni, &pi->uid, &pi->dn); + if (!BER_BVISEMPTY(&pi->dn)) { + sdn = pi->dn; + dnNormalize( 0, NULL, NULL, &sdn, &pi->dn, op->o_tmpmemctx ); + } + } + BER_BVZERO(&sdn); + if (BER_BVISEMPTY(&pi->dn)) { + rc = NSLCD_PAM_USER_UNKNOWN; + goto finish; + } + + if (BER_BVISEMPTY(&pi->pwd)) { + rc = NSLCD_PAM_IGNORE; + goto finish; + } + + /* Should only need to do this once at open time, but there's always + * the possibility that ppolicy will get loaded later. + */ + if (!ppolicy_cid) { + rc = slap_find_control_id(LDAP_CONTROL_PASSWORDPOLICYREQUEST, + &ppolicy_cid); + } + /* of course, 0 is a valid cid, but it won't be ppolicy... */ + if (ppolicy_cid) { + op->o_ctrlflag[ppolicy_cid] = SLAP_CONTROL_NONCRITICAL; + } + cb.sc_response = pam_bindcb; + cb.sc_private = pi; + op->o_callback = &cb; + op->o_dn.bv_val[0] = 0; + op->o_dn.bv_len = 0; + op->o_ndn.bv_val[0] = 0; + op->o_ndn.bv_len = 0; + op->o_tag = LDAP_REQ_BIND; + op->o_protocol = LDAP_VERSION3; + op->orb_method = LDAP_AUTH_SIMPLE; + op->orb_cred = pi->pwd; + op->o_req_dn = pi->dn; + op->o_req_ndn = pi->dn; + slap_op_time( &op->o_time, &op->o_tincr ); + rc = op->o_bd->be_bind( op, &rs ); + memset(pi->pwd.bv_val,0,pi->pwd.bv_len); + /* quirk: on successful bind, caller has to send result. we need + * to make sure callbacks run. + */ + if (rc == LDAP_SUCCESS) + send_ldap_result(op, &rs); + switch(rs.sr_err) { + case LDAP_SUCCESS: rc = NSLCD_PAM_SUCCESS; break; + case LDAP_INVALID_CREDENTIALS: rc = NSLCD_PAM_AUTH_ERR; break; + default: rc = NSLCD_PAM_AUTH_ERR; break; + } +finish: + return rc; +} + +int pam_authc(nssov_info *ni,TFILE *fp,Operation *op) +{ + int32_t tmpint32; + int rc; + slap_callback cb = {0}; + SlapReply rs = {REP_RESULT}; + char dnc[1024]; + char uidc[32]; + char svcc[256]; + char pwdc[256]; + struct berval sdn, dn; + struct paminfo pi; + + + READ_STRING_BUF2(fp,uidc,sizeof(uidc)); + pi.uid.bv_val = uidc; + pi.uid.bv_len = tmpint32; + READ_STRING_BUF2(fp,dnc,sizeof(dnc)); + pi.dn.bv_val = dnc; + pi.dn.bv_len = tmpint32; + READ_STRING_BUF2(fp,svcc,sizeof(svcc)); + pi.svc.bv_val = svcc; + pi.svc.bv_len = tmpint32; + READ_STRING_BUF2(fp,pwdc,sizeof(pwdc)); + pi.pwd.bv_val = pwdc; + pi.pwd.bv_len = tmpint32; + + Debug(LDAP_DEBUG_TRACE,"nssov_pam_authc(%s)\n",pi.uid.bv_val,0,0); + + rc = pam_do_bind(ni, fp, op, &pi); + +finish: + WRITE_INT32(fp,NSLCD_VERSION); + WRITE_INT32(fp,NSLCD_ACTION_PAM_AUTHC); + WRITE_INT32(fp,NSLCD_RESULT_SUCCESS); + WRITE_BERVAL(fp,&pi.uid); + WRITE_BERVAL(fp,&pi.dn); + WRITE_INT32(fp,rc); + WRITE_INT32(fp,pi.authz); /* authz */ + WRITE_BERVAL(fp,&pi.msg); /* authzmsg */ + return 0; +} + +static struct berval grpmsg = + BER_BVC("Access denied by group check"); +static struct berval hostmsg = + BER_BVC("Access denied for this host"); +static struct berval svcmsg = + BER_BVC("Access denied for this service"); +static struct berval uidmsg = + BER_BVC("Access denied by UID check"); + +int pam_authz(nssov_info *ni,TFILE *fp,Operation *op) +{ + struct berval dn, uid, svc, ruser, rhost, tty; + struct berval authzmsg = BER_BVNULL; + int32_t tmpint32; + char dnc[1024]; + char uidc[32]; + char svcc[256]; + char ruserc[32]; + char rhostc[256]; + char ttyc[256]; + int rc = NSLCD_PAM_SUCCESS; + Entry *e = NULL; + Attribute *a; + SlapReply rs = {REP_RESULT}; + slap_callback cb = {0}; + + READ_STRING_BUF2(fp,uidc,sizeof(uidc)); + uid.bv_val = uidc; + uid.bv_len = tmpint32; + READ_STRING_BUF2(fp,dnc,sizeof(dnc)); + dn.bv_val = dnc; + dn.bv_len = tmpint32; + READ_STRING_BUF2(fp,svcc,sizeof(svcc)); + svc.bv_val = svcc; + svc.bv_len = tmpint32; + READ_STRING_BUF2(fp,svcc,sizeof(ruserc)); + ruser.bv_val = ruserc; + ruser.bv_len = tmpint32; + READ_STRING_BUF2(fp,svcc,sizeof(rhostc)); + rhost.bv_val = rhostc; + rhost.bv_len = tmpint32; + READ_STRING_BUF2(fp,svcc,sizeof(ttyc)); + tty.bv_val = ttyc; + tty.bv_len = tmpint32; + + Debug(LDAP_DEBUG_TRACE,"nssov_pam_authz(%s)\n",dn.bv_val,0,0); + + /* We don't do authorization if they weren't authenticated by us */ + if (BER_BVISEMPTY(&dn)) { + rc = NSLCD_PAM_USER_UNKNOWN; + goto finish; + } + + /* See if they have access to the host and service */ + if ((ni->ni_pam_opts & NI_PAM_HOSTSVC) && nssov_pam_svc_ad) { + AttributeAssertion ava = ATTRIBUTEASSERTION_INIT; + struct berval hostdn = BER_BVNULL; + struct berval odn = op->o_ndn; + op->o_dn = dn; + op->o_ndn = dn; + { + nssov_mapinfo *mi = &ni->ni_maps[NM_host]; + char fbuf[1024]; + struct berval filter = {sizeof(fbuf),fbuf}; + SlapReply rs2 = {REP_RESULT}; + + /* Lookup the host entry */ + nssov_filter_byname(mi,0,&global_host_bv,&filter); + cb.sc_private = &hostdn; + cb.sc_response = nssov_name2dn_cb; + op->o_callback = &cb; + op->o_req_dn = mi->mi_base; + op->o_req_ndn = mi->mi_base; + op->ors_scope = mi->mi_scope; + op->ors_filterstr = filter; + op->ors_filter = str2filter_x(op, filter.bv_val); + op->ors_attrs = slap_anlist_no_attrs; + op->ors_tlimit = SLAP_NO_LIMIT; + op->ors_slimit = 2; + rc = op->o_bd->be_search(op, &rs2); + filter_free_x(op, op->ors_filter, 1); + + if (BER_BVISEMPTY(&hostdn) && + !BER_BVISEMPTY(&ni->ni_pam_defhost)) { + filter.bv_len = sizeof(fbuf); + filter.bv_val = fbuf; + memset(&rs2, 0, sizeof(rs2)); + rs2.sr_type = REP_RESULT; + nssov_filter_byname(mi,0,&ni->ni_pam_defhost,&filter); + op->ors_filterstr = filter; + op->ors_filter = str2filter_x(op, filter.bv_val); + rc = op->o_bd->be_search(op, &rs2); + filter_free_x(op, op->ors_filter, 1); + } + + /* no host entry, no default host -> deny */ + if (BER_BVISEMPTY(&hostdn)) { + rc = NSLCD_PAM_PERM_DENIED; + authzmsg = hostmsg; + goto finish; + } + } + + cb.sc_response = slap_null_cb; + cb.sc_private = NULL; + op->o_tag = LDAP_REQ_COMPARE; + op->o_req_dn = hostdn; + op->o_req_ndn = hostdn; + ava.aa_desc = nssov_pam_svc_ad; + ava.aa_value = svc; + op->orc_ava = &ava; + rc = op->o_bd->be_compare( op, &rs ); + if ( rs.sr_err != LDAP_COMPARE_TRUE ) { + authzmsg = svcmsg; + rc = NSLCD_PAM_PERM_DENIED; + goto finish; + } + op->o_dn = odn; + op->o_ndn = odn; + } + + /* See if they're a member of the group */ + if ((ni->ni_pam_opts & NI_PAM_USERGRP) && + !BER_BVISEMPTY(&ni->ni_pam_group_dn) && + ni->ni_pam_group_ad) { + AttributeAssertion ava = ATTRIBUTEASSERTION_INIT; + op->o_callback = &cb; + cb.sc_response = slap_null_cb; + op->o_tag = LDAP_REQ_COMPARE; + op->o_req_dn = ni->ni_pam_group_dn; + op->o_req_ndn = ni->ni_pam_group_dn; + ava.aa_desc = ni->ni_pam_group_ad; + ava.aa_value = dn; + op->orc_ava = &ava; + rc = op->o_bd->be_compare( op, &rs ); + if ( rs.sr_err != LDAP_COMPARE_TRUE ) { + authzmsg = grpmsg; + rc = NSLCD_PAM_PERM_DENIED; + goto finish; + } + } + + /* We need to check the user's entry for these bits */ + if ((ni->ni_pam_opts & (NI_PAM_USERHOST|NI_PAM_USERSVC)) || + ni->ni_pam_template_ad || + ni->ni_pam_min_uid || ni->ni_pam_max_uid ) { + rc = be_entry_get_rw( op, &dn, NULL, NULL, 0, &e ); + if (rc != LDAP_SUCCESS) { + rc = NSLCD_PAM_USER_UNKNOWN; + goto finish; + } + } + if ((ni->ni_pam_opts & NI_PAM_USERHOST) && nssov_pam_host_ad) { + a = attr_find(e->e_attrs, nssov_pam_host_ad); + if (!a || value_find_ex( nssov_pam_host_ad, + SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH, + a->a_vals, &global_host_bv, op->o_tmpmemctx )) { + rc = NSLCD_PAM_PERM_DENIED; + authzmsg = hostmsg; + goto finish; + } + } + if ((ni->ni_pam_opts & NI_PAM_USERSVC) && nssov_pam_svc_ad) { + a = attr_find(e->e_attrs, nssov_pam_svc_ad); + if (!a || value_find_ex( nssov_pam_svc_ad, + SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH, + a->a_vals, &svc, op->o_tmpmemctx )) { + rc = NSLCD_PAM_PERM_DENIED; + authzmsg = svcmsg; + goto finish; + } + } + +/* from passwd.c */ +#define UIDN_KEY 2 + + if (ni->ni_pam_min_uid || ni->ni_pam_max_uid) { + int id; + char *tmp; + nssov_mapinfo *mi = &ni->ni_maps[NM_host]; + a = attr_find(e->e_attrs, mi->mi_attrs[UIDN_KEY].an_desc); + if (!a) { + rc = NSLCD_PAM_PERM_DENIED; + authzmsg = uidmsg; + goto finish; + } + id = (int)strtol(a->a_vals[0].bv_val,&tmp,0); + if (a->a_vals[0].bv_val[0] == '\0' || *tmp != '\0') { + rc = NSLCD_PAM_PERM_DENIED; + authzmsg = uidmsg; + goto finish; + } + if ((ni->ni_pam_min_uid && id < ni->ni_pam_min_uid) || + (ni->ni_pam_max_uid && id > ni->ni_pam_max_uid)) { + rc = NSLCD_PAM_PERM_DENIED; + authzmsg = uidmsg; + goto finish; + } + } + + if (ni->ni_pam_template_ad) { + a = attr_find(e->e_attrs, ni->ni_pam_template_ad); + if (a) + uid = a->a_vals[0]; + else if (!BER_BVISEMPTY(&ni->ni_pam_template)) + uid = ni->ni_pam_template; + } + +finish: + WRITE_INT32(fp,NSLCD_VERSION); + WRITE_INT32(fp,NSLCD_ACTION_PAM_AUTHZ); + WRITE_INT32(fp,NSLCD_RESULT_SUCCESS); + WRITE_BERVAL(fp,&uid); + WRITE_BERVAL(fp,&dn); + WRITE_INT32(fp,rc); + WRITE_BERVAL(fp,&authzmsg); + if (e) { + be_entry_release_r(op, e); + } + return 0; +} + +static int pam_sess(nssov_info *ni,TFILE *fp,Operation *op,int action) +{ + struct berval dn, uid, svc, tty, rhost, ruser; + int32_t tmpint32; + char dnc[1024]; + char svcc[256]; + char uidc[32]; + char ttyc[32]; + char rhostc[256]; + char ruserc[32]; + slap_callback cb = {0}; + SlapReply rs = {REP_RESULT}; + char timebuf[LDAP_LUTIL_GENTIME_BUFSIZE]; + struct berval timestamp, bv[2], *nbv; + time_t stamp; + Modifications mod; + + READ_STRING_BUF2(fp,uidc,sizeof(uidc)); + uid.bv_val = uidc; + uid.bv_len = tmpint32; + READ_STRING_BUF2(fp,dnc,sizeof(dnc)); + dn.bv_val = dnc; + dn.bv_len = tmpint32; + READ_STRING_BUF2(fp,svcc,sizeof(svcc)); + svc.bv_val = svcc; + svc.bv_len = tmpint32; + READ_STRING_BUF2(fp,ttyc,sizeof(ttyc)); + tty.bv_val = ttyc; + tty.bv_len = tmpint32; + READ_STRING_BUF2(fp,rhostc,sizeof(rhostc)); + rhost.bv_val = rhostc; + rhost.bv_len = tmpint32; + READ_STRING_BUF2(fp,ruserc,sizeof(ruserc)); + ruser.bv_val = ruserc; + ruser.bv_len = tmpint32; + READ_INT32(fp,stamp); + + Debug(LDAP_DEBUG_TRACE,"nssov_pam_sess_%c(%s)\n", + action==NSLCD_ACTION_PAM_SESS_O ? 'o' : 'c', dn.bv_val,0); + + if (!dn.bv_len || !ni->ni_pam_sessions) return 0; + + { + int i, found=0; + for (i=0; !BER_BVISNULL(&ni->ni_pam_sessions[i]); i++) { + if (ni->ni_pam_sessions[i].bv_len != svc.bv_len) + continue; + if (!strcasecmp(ni->ni_pam_sessions[i].bv_val, svc.bv_val)) { + found = 1; + break; + } + } + if (!found) return 0; + } + + slap_op_time( &op->o_time, &op->o_tincr ); + timestamp.bv_len = sizeof(timebuf); + timestamp.bv_val = timebuf; + if (action == NSLCD_ACTION_PAM_SESS_O ) + stamp = op->o_time; + slap_timestamp( &stamp, ×tamp ); + bv[0].bv_len = timestamp.bv_len + global_host_bv.bv_len + svc.bv_len + + tty.bv_len + ruser.bv_len + rhost.bv_len + STRLENOF(" (@)"); + bv[0].bv_val = op->o_tmpalloc( bv[0].bv_len+1, op->o_tmpmemctx ); + sprintf(bv[0].bv_val, "%s %s %s %s (%s@%s)", + timestamp.bv_val, global_host_bv.bv_val, svc.bv_val, tty.bv_val, + ruser.bv_val, rhost.bv_val); + + mod.sml_numvals = 1; + mod.sml_values = bv; + BER_BVZERO(&bv[1]); + attr_normalize( ad_loginStatus, bv, &nbv, op->o_tmpmemctx ); + mod.sml_nvalues = nbv; + mod.sml_desc = ad_loginStatus; + mod.sml_op = action == NSLCD_ACTION_PAM_SESS_O ? LDAP_MOD_ADD : + LDAP_MOD_DELETE; + mod.sml_flags = SLAP_MOD_INTERNAL; + mod.sml_next = NULL; + + cb.sc_response = slap_null_cb; + op->o_callback = &cb; + op->o_tag = LDAP_REQ_MODIFY; + op->o_dn = op->o_bd->be_rootdn; + op->o_ndn = op->o_bd->be_rootndn; + op->orm_modlist = &mod; + op->orm_no_opattrs = 1; + op->o_req_dn = dn; + op->o_req_ndn = dn; + op->o_bd->be_modify( op, &rs ); + if ( mod.sml_next ) { + slap_mods_free( mod.sml_next, 1 ); + } + ber_bvarray_free_x( nbv, op->o_tmpmemctx ); + + WRITE_INT32(fp,NSLCD_VERSION); + WRITE_INT32(fp,action); + WRITE_INT32(fp,NSLCD_RESULT_SUCCESS); + WRITE_INT32(fp,op->o_time); + return 0; +} + +int pam_sess_o(nssov_info *ni,TFILE *fp,Operation *op) +{ + return pam_sess(ni,fp,op,NSLCD_ACTION_PAM_SESS_O); +} + +int pam_sess_c(nssov_info *ni,TFILE *fp,Operation *op) +{ + return pam_sess(ni,fp,op,NSLCD_ACTION_PAM_SESS_C); +} + +int pam_pwmod(nssov_info *ni,TFILE *fp,Operation *op) +{ + struct berval npw; + int32_t tmpint32; + char dnc[1024]; + char uidc[32]; + char opwc[256]; + char npwc[256]; + char svcc[256]; + struct paminfo pi; + int rc; + + READ_STRING_BUF2(fp,uidc,sizeof(uidc)); + pi.uid.bv_val = uidc; + pi.uid.bv_len = tmpint32; + READ_STRING_BUF2(fp,dnc,sizeof(dnc)); + pi.dn.bv_val = dnc; + pi.dn.bv_len = tmpint32; + READ_STRING_BUF2(fp,svcc,sizeof(svcc)); + pi.svc.bv_val = svcc; + pi.svc.bv_len = tmpint32; + READ_STRING_BUF2(fp,opwc,sizeof(opwc)); + pi.pwd.bv_val = opwc; + pi.pwd.bv_len = tmpint32; + READ_STRING_BUF2(fp,npwc,sizeof(npwc)); + npw.bv_val = npwc; + npw.bv_len = tmpint32; + + Debug(LDAP_DEBUG_TRACE,"nssov_pam_pwmod(%s), %s\n", + pi.dn.bv_val,pi.uid.bv_val,0); + + BER_BVZERO(&pi.msg); + + /* This is a prelim check */ + if (BER_BVISEMPTY(&pi.dn)) { + rc = pam_do_bind(ni,fp,op,&pi); + if (rc == NSLCD_PAM_IGNORE) + rc = NSLCD_PAM_SUCCESS; + } else { + BerElementBuffer berbuf; + BerElement *ber = (BerElement *)&berbuf; + struct berval bv; + SlapReply rs = {REP_RESULT}; + slap_callback cb = {0}; + + ber_init_w_nullc(ber, LBER_USE_DER); + ber_printf(ber, "{"); + if (!BER_BVISEMPTY(&pi.pwd)) + ber_printf(ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_OLD, + &pi.pwd); + if (!BER_BVISEMPTY(&npw)) + ber_printf(ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_NEW, + &npw); + ber_printf(ber, "N}"); + ber_flatten2(ber, &bv, 0); + op->o_tag = LDAP_REQ_EXTENDED; + op->ore_reqoid = slap_EXOP_MODIFY_PASSWD; + op->ore_reqdata = &bv; + op->o_dn = pi.dn; + op->o_ndn = pi.dn; + op->o_callback = &cb; + op->o_conn->c_authz_backend = op->o_bd; + cb.sc_response = slap_null_cb; + op->o_bd = frontendDB; + rc = op->o_bd->be_extended(op, &rs); + if (rs.sr_text) + ber_str2bv(rs.sr_text, 0, 0, &pi.msg); + if (rc == LDAP_SUCCESS) + rc = NSLCD_PAM_SUCCESS; + else + rc = NSLCD_PAM_PERM_DENIED; + } + WRITE_INT32(fp,NSLCD_VERSION); + WRITE_INT32(fp,NSLCD_ACTION_PAM_PWMOD); + WRITE_INT32(fp,NSLCD_RESULT_SUCCESS); + WRITE_BERVAL(fp,&pi.uid); + WRITE_BERVAL(fp,&pi.dn); + WRITE_INT32(fp,rc); + WRITE_BERVAL(fp,&pi.msg); + return 0; +} + +int nssov_pam_init() +{ + int code = 0; + if (!ad_loginStatus) + code = register_at( at_loginStatus, &ad_loginStatus, 0 ); + return code; +} diff --git a/contrib/slapd-modules/nssov/passwd.c b/contrib/slapd-modules/nssov/passwd.c index 4897ac286b..20ef4d67fb 100644 --- a/contrib/slapd-modules/nssov/passwd.c +++ b/contrib/slapd-modules/nssov/passwd.c @@ -143,7 +143,7 @@ int nssov_dn2uid(Operation *op,nssov_info *ni,struct berval *dn,struct berval *u return 0; } -static int uid2dn_cb(Operation *op,SlapReply *rs) +int nssov_name2dn_cb(Operation *op,SlapReply *rs) { if ( rs->sr_type == REP_SEARCH ) { @@ -175,7 +175,7 @@ int nssov_uid2dn(Operation *op,nssov_info *ni,struct berval *uid,struct berval * nssov_filter_byid(mi,UID_KEY,uid,&filter); BER_BVZERO(dn); cb.sc_private = dn; - cb.sc_response = uid2dn_cb; + cb.sc_response = nssov_name2dn_cb; op2 = *op; op2.o_callback = &cb; op2.o_req_dn = mi->mi_base; @@ -188,7 +188,7 @@ int nssov_uid2dn(Operation *op,nssov_info *ni,struct berval *uid,struct berval * op2.ors_slimit = SLAP_NO_LIMIT; rc = op2.o_bd->be_search( &op2, &rs ); filter_free_x( op, op2.ors_filter, 1 ); - return rc == LDAP_SUCCESS; + return rc == LDAP_SUCCESS && !BER_BVISNULL(dn); } /* the maximum number of uidNumber attributes per entry */ @@ -223,7 +223,7 @@ static int write_passwd(nssov_passwd_cbp *cbp,Entry *entry) a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[UID_KEY].an_desc); if (!a) { - Debug(LDAP_DEBUG_ANY,"passwd entry %s does not contain %s value", + Debug(LDAP_DEBUG_ANY,"passwd entry %s does not contain %s value\n", entry->e_name.bv_val, cbp->mi->mi_attrs[UID_KEY].an_desc->ad_cname.bv_val,0); return 0; } @@ -264,7 +264,7 @@ static int write_passwd(nssov_passwd_cbp *cbp,Entry *entry) a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[UIDN_KEY].an_desc); if ( !a ) { - Debug(LDAP_DEBUG_ANY,"passwd entry %s does not contain %s value", + Debug(LDAP_DEBUG_ANY,"passwd entry %s does not contain %s value\n", entry->e_name.bv_val, cbp->mi->mi_attrs[UIDN_KEY].an_desc->ad_cname.bv_val,0); return 0; } @@ -280,19 +280,19 @@ static int write_passwd(nssov_passwd_cbp *cbp,Entry *entry) a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[GIDN_KEY].an_desc); if (!a) { - Debug(LDAP_DEBUG_ANY,"passwd entry %s does not contain %s value", + Debug(LDAP_DEBUG_ANY,"passwd entry %s does not contain %s value\n", entry->e_name.bv_val, cbp->mi->mi_attrs[GIDN_KEY].an_desc->ad_cname.bv_val,0); return 0; } else if (a->a_numvals != 1) { - Debug(LDAP_DEBUG_ANY,"passwd entry %s contains multiple %s values", + Debug(LDAP_DEBUG_ANY,"passwd entry %s contains multiple %s values\n", entry->e_name.bv_val, cbp->mi->mi_attrs[GIDN_KEY].an_desc->ad_cname.bv_val,0); } gid=(gid_t)strtol(a->a_vals[0].bv_val,&tmp,0); if ((a->a_vals[0].bv_val[0]=='\0')||(*tmp!='\0')) { - Debug(LDAP_DEBUG_ANY,"passwd entry %s contains non-numeric %s value", + Debug(LDAP_DEBUG_ANY,"passwd entry %s contains non-numeric %s value\n", entry->e_name.bv_val, cbp->mi->mi_attrs[GIDN_KEY].an_desc->ad_cname.bv_val,0); return 0; } @@ -302,7 +302,7 @@ static int write_passwd(nssov_passwd_cbp *cbp,Entry *entry) a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[CN_KEY].an_desc); if (!a || !a->a_numvals) { - Debug(LDAP_DEBUG_ANY,"passwd entry %s does not contain %s or %s value", + Debug(LDAP_DEBUG_ANY,"passwd entry %s does not contain %s or %s value\n", entry->e_name.bv_val, cbp->mi->mi_attrs[GEC_KEY].an_desc->ad_cname.bv_val, cbp->mi->mi_attrs[CN_KEY].an_desc->ad_cname.bv_val); @@ -310,7 +310,7 @@ static int write_passwd(nssov_passwd_cbp *cbp,Entry *entry) } else if (a->a_numvals > 1) { - Debug(LDAP_DEBUG_ANY,"passwd entry %s contains multiple %s or %s values", + Debug(LDAP_DEBUG_ANY,"passwd entry %s contains multiple %s or %s values\n", entry->e_name.bv_val, cbp->mi->mi_attrs[GEC_KEY].an_desc->ad_cname.bv_val, cbp->mi->mi_attrs[CN_KEY].an_desc->ad_cname.bv_val); @@ -320,7 +320,7 @@ static int write_passwd(nssov_passwd_cbp *cbp,Entry *entry) a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[DIR_KEY].an_desc); if (!a) { - Debug(LDAP_DEBUG_ANY,"passwd entry %s does not contain %s value", + Debug(LDAP_DEBUG_ANY,"passwd entry %s does not contain %s value\n", entry->e_name.bv_val, cbp->mi->mi_attrs[DIR_KEY].an_desc->ad_cname.bv_val,0); homedir=default_passwd_homeDirectory; } @@ -328,7 +328,7 @@ static int write_passwd(nssov_passwd_cbp *cbp,Entry *entry) { if (a->a_numvals > 1) { - Debug(LDAP_DEBUG_ANY,"passwd entry %s contains multiple %s values", + Debug(LDAP_DEBUG_ANY,"passwd entry %s contains multiple %s values\n", entry->e_name.bv_val, cbp->mi->mi_attrs[DIR_KEY].an_desc->ad_cname.bv_val,0); } homedir=a->a_vals[0]; @@ -345,7 +345,7 @@ static int write_passwd(nssov_passwd_cbp *cbp,Entry *entry) { if (a->a_numvals > 1) { - Debug(LDAP_DEBUG_ANY,"passwd entry %s contains multiple %s values", + Debug(LDAP_DEBUG_ANY,"passwd entry %s contains multiple %s values\n", entry->e_name.bv_val, cbp->mi->mi_attrs[SHL_KEY].an_desc->ad_cname.bv_val,0); } shell=a->a_vals[0]; @@ -357,7 +357,7 @@ static int write_passwd(nssov_passwd_cbp *cbp,Entry *entry) { if (!isvalidusername(&names[i])) { - Debug(LDAP_DEBUG_ANY,"nssov: passwd entry %s contains invalid user name: \"%s\"", + Debug(LDAP_DEBUG_ANY,"nssov: passwd entry %s contains invalid user name: \"%s\"\n", entry->e_name.bv_val,names[i].bv_val,0); } else @@ -368,7 +368,7 @@ static int write_passwd(nssov_passwd_cbp *cbp,Entry *entry) uid_t uid; uid = strtol(uids[j].bv_val, &tmp, 0); if ( *tmp ) { - Debug(LDAP_DEBUG_ANY,"nssov: passwd entry %s contains non-numeric %s value: \"%s\"", + Debug(LDAP_DEBUG_ANY,"nssov: passwd entry %s contains non-numeric %s value: \"%s\"\n", entry->e_name.bv_val, cbp->mi->mi_attrs[UIDN_KEY].an_desc->ad_cname.bv_val, names[i].bv_val); continue; @@ -398,11 +398,11 @@ NSSOV_HANDLE( cbp.name.bv_len = tmpint32; cbp.name.bv_val = cbp.buf; if (!isvalidusername(&cbp.name)) { - Debug(LDAP_DEBUG_ANY,"nssov_passwd_byname(%s): invalid user name",cbp.name.bv_val,0,0); + Debug(LDAP_DEBUG_ANY,"nssov_passwd_byname(%s): invalid user name\n",cbp.name.bv_val,0,0); return -1; } BER_BVZERO(&cbp.id); , - Debug(LDAP_DEBUG_TRACE,"nssov_passwd_byname(%s)",cbp.name.bv_val,0,0);, + Debug(LDAP_DEBUG_TRACE,"nssov_passwd_byname(%s)\n",cbp.name.bv_val,0,0);, NSLCD_ACTION_PASSWD_BYNAME, nssov_filter_byname(cbp.mi,UID_KEY,&cbp.name,&filter) ) @@ -417,7 +417,7 @@ NSSOV_HANDLE( cbp.id.bv_val = cbp.buf; cbp.id.bv_len = snprintf(cbp.buf,sizeof(cbp.buf),"%d",uid); BER_BVZERO(&cbp.name);, - Debug(LDAP_DEBUG_TRACE,"nssov_passwd_byuid(%s)",cbp.id.bv_val,0,0);, + Debug(LDAP_DEBUG_TRACE,"nssov_passwd_byuid(%s)\n",cbp.id.bv_val,0,0);, NSLCD_ACTION_PASSWD_BYUID, nssov_filter_byid(cbp.mi,UIDN_KEY,&cbp.id,&filter) ) @@ -428,7 +428,7 @@ NSSOV_HANDLE( /* no parameters to read */ BER_BVZERO(&cbp.name); BER_BVZERO(&cbp.id);, - Debug(LDAP_DEBUG_TRACE,"nssov_passwd_all()",0,0,0);, + Debug(LDAP_DEBUG_TRACE,"nssov_passwd_all()\n",0,0,0);, NSLCD_ACTION_PASSWD_ALL, (filter=cbp.mi->mi_filter,0) ) diff --git a/contrib/slapd-modules/nssov/protocol.c b/contrib/slapd-modules/nssov/protocol.c index 54a176bc2d..6e6e5b8b8b 100644 --- a/contrib/slapd-modules/nssov/protocol.c +++ b/contrib/slapd-modules/nssov/protocol.c @@ -59,7 +59,7 @@ static int write_protocol(nssov_protocol_cbp *cbp,Entry *entry) a = attr_find( entry->e_attrs, cbp->mi->mi_attrs[0].an_desc ); if ( !a || !a->a_vals ) { - Debug(LDAP_DEBUG_ANY,"protocol entry %s does not contain %s value", + Debug(LDAP_DEBUG_ANY,"protocol entry %s does not contain %s value\n", entry->e_name.bv_val, cbp->mi->mi_attrs[0].an_desc->ad_cname.bv_val, 0 ); return 0; } @@ -82,17 +82,17 @@ static int write_protocol(nssov_protocol_cbp *cbp,Entry *entry) a = attr_find( entry->e_attrs, cbp->mi->mi_attrs[1].an_desc ); if ( !a || !a->a_vals ) { - Debug(LDAP_DEBUG_ANY,"protocol entry %s does not contain %s value", + Debug(LDAP_DEBUG_ANY,"protocol entry %s does not contain %s value\n", entry->e_name.bv_val, cbp->mi->mi_attrs[1].an_desc->ad_cname.bv_val, 0 ); return 0; } else if ( a->a_numvals > 1 ) { - Debug(LDAP_DEBUG_ANY,"protocol entry %s contains multiple %s values", + Debug(LDAP_DEBUG_ANY,"protocol entry %s contains multiple %s values\n", entry->e_name.bv_val, cbp->mi->mi_attrs[1].an_desc->ad_cname.bv_val, 0 ); } proto=(int)strtol(a->a_vals[0].bv_val,&tmp,0); if (*tmp) { - Debug(LDAP_DEBUG_ANY,"protocol entry %s contains non-numeric %s value", + Debug(LDAP_DEBUG_ANY,"protocol entry %s contains non-numeric %s value\n", entry->e_name.bv_val, cbp->mi->mi_attrs[1].an_desc->ad_cname.bv_val, 0 ); return 0; } @@ -123,7 +123,7 @@ NSSOV_HANDLE( READ_STRING_BUF2(fp,cbp.buf,sizeof(cbp.buf)); cbp.name.bv_len = tmpint32; cbp.name.bv_val = cbp.buf;, - Debug(LDAP_DEBUG_TRACE,"nssov_protocol_byname(%s)",cbp.name.bv_val,0,0);, + Debug(LDAP_DEBUG_TRACE,"nssov_protocol_byname(%s)\n",cbp.name.bv_val,0,0);, NSLCD_ACTION_PROTOCOL_BYNAME, nssov_filter_byname(cbp.mi,0,&cbp.name,&filter) ) @@ -138,7 +138,7 @@ NSSOV_HANDLE( cbp.numb.bv_val = cbp.buf; cbp.numb.bv_len = snprintf(cbp.buf,sizeof(cbp.buf),"%d",protocol); BER_BVZERO(&cbp.name);, - Debug(LDAP_DEBUG_TRACE,"nssov_protocol_bynumber(%s)",cbp.numb.bv_val,0,0);, + Debug(LDAP_DEBUG_TRACE,"nssov_protocol_bynumber(%s)\n",cbp.numb.bv_val,0,0);, NSLCD_ACTION_PROTOCOL_BYNUMBER, nssov_filter_byid(cbp.mi,1,&cbp.numb,&filter) ) @@ -147,7 +147,7 @@ NSSOV_HANDLE( protocol,all, struct berval filter; /* no parameters to read */, - Debug(LDAP_DEBUG_TRACE,"nssov_protocol_all()",0,0,0);, + Debug(LDAP_DEBUG_TRACE,"nssov_protocol_all()\n",0,0,0);, NSLCD_ACTION_PROTOCOL_ALL, (filter=cbp.mi->mi_filter,0) ) diff --git a/contrib/slapd-modules/nssov/rpc.c b/contrib/slapd-modules/nssov/rpc.c index b9e8ca8875..b86d913180 100644 --- a/contrib/slapd-modules/nssov/rpc.c +++ b/contrib/slapd-modules/nssov/rpc.c @@ -62,7 +62,7 @@ static int write_rpc(nssov_rpc_cbp *cbp,Entry *entry) a = attr_find( entry->e_attrs, cbp->mi->mi_attrs[0].an_desc ); if ( !a || !a->a_vals ) { - Debug(LDAP_DEBUG_ANY,"rpc entry %s does not contain %s value", + Debug(LDAP_DEBUG_ANY,"rpc entry %s does not contain %s value\n", entry->e_name.bv_val, cbp->mi->mi_attrs[0].an_desc->ad_cname.bv_val, 0 ); return 0; } @@ -85,17 +85,17 @@ static int write_rpc(nssov_rpc_cbp *cbp,Entry *entry) a = attr_find( entry->e_attrs, cbp->mi->mi_attrs[1].an_desc ); if ( !a || !a->a_vals ) { - Debug(LDAP_DEBUG_ANY,"rpc entry %s does not contain %s value", + Debug(LDAP_DEBUG_ANY,"rpc entry %s does not contain %s value\n", entry->e_name.bv_val, cbp->mi->mi_attrs[1].an_desc->ad_cname.bv_val, 0 ); return 0; } else if ( a->a_numvals > 1 ) { - Debug(LDAP_DEBUG_ANY,"rpc entry %s contains multiple %s values", + Debug(LDAP_DEBUG_ANY,"rpc entry %s contains multiple %s values\n", entry->e_name.bv_val, cbp->mi->mi_attrs[1].an_desc->ad_cname.bv_val, 0 ); } number=(int)strtol(a->a_vals[0].bv_val,&tmp,0); if (*tmp) { - Debug(LDAP_DEBUG_ANY,"rpc entry %s contains non-numeric %s value", + Debug(LDAP_DEBUG_ANY,"rpc entry %s contains non-numeric %s value\n", entry->e_name.bv_val, cbp->mi->mi_attrs[1].an_desc->ad_cname.bv_val, 0 ); return 0; } @@ -126,7 +126,7 @@ NSSOV_HANDLE( READ_STRING_BUF2(fp,cbp.buf,sizeof(cbp.buf)); cbp.name.bv_len = tmpint32; cbp.name.bv_val = cbp.buf;, - Debug(LDAP_DEBUG_TRACE,"nssov_rpc_byname(%s)",cbp.name.bv_val,0,0);, + Debug(LDAP_DEBUG_TRACE,"nssov_rpc_byname(%s)\n",cbp.name.bv_val,0,0);, NSLCD_ACTION_RPC_BYNAME, nssov_filter_byname(cbp.mi,0,&cbp.name,&filter) ) @@ -141,7 +141,7 @@ NSSOV_HANDLE( cbp.numb.bv_val = cbp.buf; cbp.numb.bv_len = snprintf(cbp.buf,sizeof(cbp.buf),"%d",number); BER_BVZERO(&cbp.name);, - Debug(LDAP_DEBUG_TRACE,"nssov_rpc_bynumber(%d)",cbp.numb.bv_val,0,0);, + Debug(LDAP_DEBUG_TRACE,"nssov_rpc_bynumber(%s)\n",cbp.numb.bv_val,0,0);, NSLCD_ACTION_RPC_BYNUMBER, nssov_filter_byid(cbp.mi,1,&cbp.numb,&filter) ) @@ -150,7 +150,7 @@ NSSOV_HANDLE( rpc,all, struct berval filter; /* no parameters to read */, - Debug(LDAP_DEBUG_TRACE,"nssov_rpc_all()",0,0,0);, + Debug(LDAP_DEBUG_TRACE,"nssov_rpc_all()\n",0,0,0);, NSLCD_ACTION_RPC_ALL, (filter=cbp.mi->mi_filter,0) ) diff --git a/contrib/slapd-modules/nssov/service.c b/contrib/slapd-modules/nssov/service.c index ceaf901187..ac5390a180 100644 --- a/contrib/slapd-modules/nssov/service.c +++ b/contrib/slapd-modules/nssov/service.c @@ -124,7 +124,7 @@ static int write_service(nssov_service_cbp *cbp,Entry *entry) a = attr_find( entry->e_attrs, cbp->mi->mi_attrs[0].an_desc ); if ( !a || !a->a_vals ) { - Debug(LDAP_DEBUG_ANY,"service entry %s does not contain %s value", + Debug(LDAP_DEBUG_ANY,"service entry %s does not contain %s value\n", entry->e_name.bv_val, cbp->mi->mi_attrs[0].an_desc->ad_cname.bv_val, 0 ); return 0; } @@ -147,17 +147,17 @@ static int write_service(nssov_service_cbp *cbp,Entry *entry) a = attr_find( entry->e_attrs, cbp->mi->mi_attrs[1].an_desc ); if ( !a || !a->a_vals ) { - Debug(LDAP_DEBUG_ANY,"service entry %s does not contain %s value", + Debug(LDAP_DEBUG_ANY,"service entry %s does not contain %s value\n", entry->e_name.bv_val, cbp->mi->mi_attrs[1].an_desc->ad_cname.bv_val, 0 ); return 0; } else if ( a->a_numvals > 1 ) { - Debug(LDAP_DEBUG_ANY,"service entry %s contains multiple %s values", + Debug(LDAP_DEBUG_ANY,"service entry %s contains multiple %s values\n", entry->e_name.bv_val, cbp->mi->mi_attrs[1].an_desc->ad_cname.bv_val, 0 ); } port=(int)strtol(a->a_vals[0].bv_val,&tmp,0); if (*tmp) { - Debug(LDAP_DEBUG_ANY,"service entry %s contains non-numeric %s value", + Debug(LDAP_DEBUG_ANY,"service entry %s contains non-numeric %s value\n", entry->e_name.bv_val, cbp->mi->mi_attrs[1].an_desc->ad_cname.bv_val, 0 ); return 0; } @@ -167,7 +167,7 @@ static int write_service(nssov_service_cbp *cbp,Entry *entry) a = attr_find( entry->e_attrs, cbp->mi->mi_attrs[2].an_desc ); if ( !a || !a->a_vals ) { - Debug(LDAP_DEBUG_ANY,"service entry %s does not contain %s value", + Debug(LDAP_DEBUG_ANY,"service entry %s does not contain %s value\n", entry->e_name.bv_val, cbp->mi->mi_attrs[2].an_desc->ad_cname.bv_val, 0 ); return 0; } @@ -215,7 +215,7 @@ NSSOV_HANDLE( READ_STRING_BUF2(fp,cbp.pbuf,sizeof(cbp.pbuf)); cbp.prot.bv_len = tmpint32; cbp.prot.bv_val = tmpint32 ? cbp.pbuf : NULL;, - Debug(LDAP_DEBUG_TRACE,"nssov_service_byname(%s,%s)",cbp.name.bv_val,cbp.prot.bv_val,0);, + Debug(LDAP_DEBUG_TRACE,"nssov_service_byname(%s,%s)\n",cbp.name.bv_val,cbp.prot.bv_val,0);, NSLCD_ACTION_SERVICE_BYNAME, mkfilter_service_byname(cbp.mi,&cbp.name,&cbp.prot,&filter) ) @@ -232,7 +232,7 @@ NSSOV_HANDLE( READ_STRING_BUF2(fp,cbp.pbuf,sizeof(cbp.pbuf)); cbp.prot.bv_len = tmpint32; cbp.prot.bv_val = tmpint32 ? cbp.pbuf : NULL;, - Debug(LDAP_DEBUG_TRACE,"nssov_service_bynumber(%s,%s)",cbp.name.bv_val,cbp.prot.bv_val,0);, + Debug(LDAP_DEBUG_TRACE,"nssov_service_bynumber(%s,%s)\n",cbp.name.bv_val,cbp.prot.bv_val,0);, NSLCD_ACTION_SERVICE_BYNUMBER, mkfilter_service_bynumber(cbp.mi,&cbp.name,&cbp.prot,&filter) ) @@ -242,7 +242,7 @@ NSSOV_HANDLE( struct berval filter; /* no parameters to read */ BER_BVZERO(&cbp.prot);, - Debug(LDAP_DEBUG_TRACE,"nssov_service_all()",0,0,0);, + Debug(LDAP_DEBUG_TRACE,"nssov_service_all()\n",0,0,0);, NSLCD_ACTION_SERVICE_ALL, (filter=cbp.mi->mi_filter,0) ) diff --git a/contrib/slapd-modules/nssov/shadow.c b/contrib/slapd-modules/nssov/shadow.c index 49fd6fbd3f..f331e59cd1 100644 --- a/contrib/slapd-modules/nssov/shadow.c +++ b/contrib/slapd-modules/nssov/shadow.c @@ -91,7 +91,7 @@ static long to_date(struct berval *date,AttributeDescription *attr) value=strtol(buffer,&tmp,0); if ((buffer[0]=='\0')||(*tmp!='\0')) { - Debug(LDAP_DEBUG_ANY,"shadow entry contains non-numeric %s value", + Debug(LDAP_DEBUG_ANY,"shadow entry contains non-numeric %s value\n", attr->ad_cname.bv_val,0,0); return 0; } @@ -102,7 +102,7 @@ static long to_date(struct berval *date,AttributeDescription *attr) value=strtol(date->bv_val,&tmp,0); if ((date->bv_val[0]=='\0')||(*tmp!='\0')) { - Debug(LDAP_DEBUG_ANY,"shadow entry contains non-numeric %s value", + Debug(LDAP_DEBUG_ANY,"shadow entry contains non-numeric %s value\n", attr->ad_cname.bv_val,0,0); return 0; } @@ -121,13 +121,13 @@ static long to_date(struct berval *date,AttributeDescription *attr) { \ if (a->a_numvals > 1) \ { \ - Debug(LDAP_DEBUG_ANY,"shadow entry %s contains multiple %s values", \ + Debug(LDAP_DEBUG_ANY,"shadow entry %s contains multiple %s values\n", \ entry->e_name.bv_val, cbp->mi->mi_attrs[key].an_desc->ad_cname.bv_val,0); \ } \ var=strtol(a->a_vals[0].bv_val,&tmp,0); \ if ((a->a_vals[0].bv_val[0]=='\0')||(*tmp!='\0')) \ { \ - Debug(LDAP_DEBUG_ANY,"shadow entry %s contains non-numeric %s value", \ + Debug(LDAP_DEBUG_ANY,"shadow entry %s contains non-numeric %s value\n", \ entry->e_name.bv_val, cbp->mi->mi_attrs[key].an_desc->ad_cname.bv_val,0); \ return 0; \ } \ @@ -141,7 +141,7 @@ static long to_date(struct berval *date,AttributeDescription *attr) { \ if (a->a_numvals > 1) \ { \ - Debug(LDAP_DEBUG_ANY,"shadow entry %s contains multiple %s values", \ + Debug(LDAP_DEBUG_ANY,"shadow entry %s contains multiple %s values\n", \ entry->e_name.bv_val, cbp->mi->mi_attrs[key].an_desc->ad_cname.bv_val,0); \ } \ var=to_date(&a->a_vals[0],cbp->mi->mi_attrs[key].an_desc); \ @@ -173,7 +173,7 @@ static int write_shadow(nssov_shadow_cbp *cbp,Entry *entry) a = attr_find(entry->e_attrs, cbp->mi->mi_attrs[UID_KEY].an_desc); if (!a) { - Debug(LDAP_DEBUG_ANY,"shadow entry %s does not contain %s value", + Debug(LDAP_DEBUG_ANY,"shadow entry %s does not contain %s value\n", entry->e_name.bv_val, cbp->mi->mi_attrs[UID_KEY].an_desc->ad_cname.bv_val,0); return 0; } @@ -239,7 +239,7 @@ NSSOV_HANDLE( READ_STRING_BUF2(fp,cbp.buf,sizeof(cbp.buf));, cbp.name.bv_len = tmpint32; cbp.name.bv_val = cbp.buf; - Debug(LDAP_DEBUG_ANY,"nssov_shadow_byname(%s)",cbp.name.bv_val,0,0);, + Debug(LDAP_DEBUG_ANY,"nssov_shadow_byname(%s)\n",cbp.name.bv_val,0,0);, NSLCD_ACTION_SHADOW_BYNAME, nssov_filter_byname(cbp.mi,UID_KEY,&cbp.name,&filter) ) @@ -249,7 +249,7 @@ NSSOV_HANDLE( struct berval filter; /* no parameters to read */ BER_BVZERO(&cbp.name);, - Debug(LDAP_DEBUG_ANY,"nssov_shadow_all()",0,0,0);, + Debug(LDAP_DEBUG_ANY,"nssov_shadow_all()\n",0,0,0);, NSLCD_ACTION_SHADOW_ALL, (filter=cbp.mi->mi_filter,0) ) diff --git a/contrib/slapd-modules/nssov/slapo-nssov.5 b/contrib/slapd-modules/nssov/slapo-nssov.5 new file mode 100644 index 0000000000..7e45d776df --- /dev/null +++ b/contrib/slapd-modules/nssov/slapo-nssov.5 @@ -0,0 +1,299 @@ +.TH SLAPO-NSSOV 5 "RELEASEDATE" "OpenLDAP LDVERSION" +.\" Copyright 1998-2009 The OpenLDAP Foundation, All Rights Reserved. +.\" Copying restrictions apply. See the COPYRIGHT file. +.\" $OpenLDAP$ +.SH NAME +slapo-nssov \- NSS and PAM requests through a local Unix Domain socket +.SH SYNOPSIS +ETCDIR/slapd.conf +.SH DESCRIPTION +The +.B nssov +overlay to +.BR slapd (8) +services NSS and PAM requests through a local Unix Domain socket. +It uses the same IPC protocol as Arthur de Jong's nss-ldapd, and +a complete copy of the nss-ldapd source is included along with the +nssov source code. +.LP +Using a separate IPC protocol for NSS and PAM requests eliminates the +libldap dependencies/clashes that the current pam_ldap/nss_ldap solutions +all suffer from. Both the original nss-ldapd and this nssov solution +are free from these library issues. +.LP +Unlike nss-ldapd, since this overlay executes inside slapd it allows for +the possibility of sophisticated caching, without any of the weaknesses of +nscd and other related caching solutions. E.g., a remote LDAP database can +be accessed using back-ldap with proxy caching (see +.BR slapd-ldap (5) +and +.BR slapo-pcache (5) +) to leverage back-ldap's +connection pooling as well as pcache's persistent caching, to provide +high performance and a measure of support for disconnected operation. +Alternatively, cache considerations can be completely eliminated by running +a regular database with syncrepl to maintain synchronization with a remote +LDAP database. +.LP +Another major benefit of nssov is that it allows all security policy to be +administered centrally via LDAP, instead of having fragile rules scattered +across multiple flat files. As such, there is no client-side configuration at +all for the NSS/PAM stub libraries. (The stubs talk to the server via a Unix +domain socket whose path is hardcoded to /var/run/nslcd/). As a side benefit, +this can finally eliminate the perpetual confusion between OpenLDAP's +ldap.conf file in ETCDIR/ldap.conf and the similarly named files typically +used by pam_ldap and nss_ldap. +.LP +User authentication is performed by internal simple Binds. User authorization +leverages the slapd ACL engine, which offers much more power and flexibility +than the simple group/hostname checks in the old pam_ldap code. +.LP +To use this code, you will need the client-side stub library from +nss-ldapd (which resides in nss-ldapd/nss). You will not need the +nslcd daemon; this overlay replaces that part. You should already +be familiar with the [RFC2307] and [RFC2307bis] schema to use this +overlay. See the +.B nss-ldapd/README +for more information on the schema and which features are supported. +.LP +You will also need to include the nis.schema in your slapd configuration +for RFC2307 support. If you wish to use RFC2307bis you will need a slightly +different schema. You will also need the ldapns.schema for PAM authorization +management. +.LP +You must select +.B ldap +in the appropriate services in +.I /etc/nsswitch.conf +in order for these NSS features to take effect. Likewise, you must +enable +.B pam_ldap +for the authenticate, account, session, and password services in +.I /etc/pam.conf +or +.I /etc/pam.d +for these PAM features to take effect. + +.TP +.B overlay nssov +This directive adds the nssov overlay to the current backend. +.TP +.B nssov-ssd +This directive configures a Service Search Descriptor (SSD) for each NSS +service that will be used. The may be one of +.RS +.nf + alias + ether + group + host + netgroup + network + passwd + protocol + rpc + service + shadow +.fi +.RE +and the must be of the form +.RS +.TP +.B ldap:///[][??[][?]] +.RE +The +.B +will default to the first suffix of the current database. +The +.B +defaults to "subtree". The default +.B +depends on which service is being used. +.TP +.B nssov-map +If the local database is actually a proxy to a foreign LDAP server, some +mapping of schema may be needed. This directive allows some simple attribute +substitutions to be performed. See the +.B nss-ldapd/README +for the original attribute names used in this code. +.TP +.B nssov-pam