summaryrefslogtreecommitdiff
path: root/usr/src/lib
diff options
context:
space:
mode:
authorMichen Chang <Michen.Chang@Sun.COM>2009-02-13 18:18:56 -0800
committerMichen Chang <Michen.Chang@Sun.COM>2009-02-13 18:18:56 -0800
commitdd1104fbe0f0f41434502f335b9f0b34999f771c (patch)
tree57c95d64bc40cebf2b145329e1f49e811352d502 /usr/src/lib
parentd68ef20e3fe871e73146fc684d29d335521dcd99 (diff)
downloadillumos-joyent-dd1104fbe0f0f41434502f335b9f0b34999f771c.tar.gz
PSARC 2008/745 nss_ldap shadowAccount support
6715171 nss_ldap and passwdutil do not support all shadowAccount attributes 6797378 'ldapaddent -d passwd' does not print 'x' for the password field 6783712 libsldap fails to set correct version number for V1 profile
Diffstat (limited to 'usr/src/lib')
-rw-r--r--usr/src/lib/libsldap/common/mapfile-vers34
-rw-r--r--usr/src/lib/libsldap/common/ns_cache_door.h14
-rw-r--r--usr/src/lib/libsldap/common/ns_config.c79
-rw-r--r--usr/src/lib/libsldap/common/ns_confmgr.c56
-rw-r--r--usr/src/lib/libsldap/common/ns_internal.h11
-rw-r--r--usr/src/lib/libsldap/common/ns_sldap.h27
-rw-r--r--usr/src/lib/libsldap/common/ns_writes.c308
-rw-r--r--usr/src/lib/nsswitch/ldap/common/getspent.c100
-rw-r--r--usr/src/lib/passwdutil/__failed_count.c46
-rw-r--r--usr/src/lib/passwdutil/ldap_attr.c860
-rw-r--r--usr/src/lib/passwdutil/passwdutil.h3
11 files changed, 1275 insertions, 263 deletions
diff --git a/usr/src/lib/libsldap/common/mapfile-vers b/usr/src/lib/libsldap/common/mapfile-vers
index f58a9328d4..e043513adf 100644
--- a/usr/src/lib/libsldap/common/mapfile-vers
+++ b/usr/src/lib/libsldap/common/mapfile-vers
@@ -22,19 +22,6 @@
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-
-#
-# MAPFILE HEADER START
-#
-# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
-# Object versioning must comply with the rules detailed in
-#
-# usr/src/lib/README.mapfiles
-#
-# You should not be making modifications here until you've read the most current
-# copy of that file. If you need help, contact a gatekeeper for guidance.
-#
-# MAPFILE HEADER END
#
# There really should be only one SUNWprivate version.
@@ -42,22 +29,23 @@
SUNWprivate_1.1 {
global:
- __ns_ldap_initStandalone;
- __ns_ldap_getConnectionInfoFromDUA;
- __ns_ldap_getRootDSE;
- __ns_ldap_pingOfflineServers;
__ns_ldap_cancelStandalone;
- __ns_ldap_initAuth;
+ __ns_ldap_check_all_preq;
+ __ns_ldap_check_dns_preq;
+ __ns_ldap_check_gssapi_preq;
__ns_ldap_getAcctMgmt;
- __s_api_get_canonical_name;
__ns_ldap_getAttrStruct;
+ __ns_ldap_getConnectionInfoFromDUA;
+ __ns_ldap_getRootDSE;
+ __ns_ldap_initAuth;
+ __ns_ldap_initStandalone;
+ __ns_ldap_is_shadow_update_enabled;
+ __ns_ldap_pingOfflineServers;
__ns_ldap_self_gssapi_config;
__ns_ldap_self_gssapi_only_set;
- __ns_ldap_check_dns_preq;
- __ns_ldap_check_gssapi_preq;
- __ns_ldap_check_all_preq;
- __s_api_ip2hostname;
+ __s_api_get_canonical_name;
__s_api_hostname2ip;
+ __s_api_ip2hostname;
} SUNWprivate_1.0;
SUNWprivate_1.0 {
diff --git a/usr/src/lib/libsldap/common/ns_cache_door.h b/usr/src/lib/libsldap/common/ns_cache_door.h
index 391394cbe7..52599534af 100644
--- a/usr/src/lib/libsldap/common/ns_cache_door.h
+++ b/usr/src/lib/libsldap/common/ns_cache_door.h
@@ -19,15 +19,13 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _NS_CACHE_DOOR_H
#define _NS_CACHE_DOOR_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* Definitions for client side of doors-based ldap caching
*/
@@ -96,6 +94,13 @@ typedef struct ldap_config_out {
char config_str[sizeof (int)]; /* real size is data_size */
} ldap_config_out_t;
+typedef struct ldap_admin_mod_result {
+ uint32_t ns_err; /* ns_ldap error code */
+ uint32_t status; /* error status */
+ uint32_t msg_size; /* length of error message */
+ char msg[sizeof (int)]; /* real size is msg_size */
+} ldap_admin_mod_result_t;
+
/*
* structure returned by server for all calls
*/
@@ -116,6 +121,7 @@ typedef struct {
ldap_strlist_t strlist;
ldap_config_out_t config_str;
ldap_get_change_out_t changes;
+ ldap_admin_mod_result_t admin_result;
} ldap_u;
} ldap_return_t;
@@ -187,6 +193,8 @@ typedef union {
#define GETCACHESTAT 24
/* Configuration change or server status change notification */
#define GETSTATUSCHANGE 25
+ /* perform admin modify via ldap_cachemgr */
+#define ADMINMODIFY 26
/*
* GETLDAPSERVER request flags
diff --git a/usr/src/lib/libsldap/common/ns_config.c b/usr/src/lib/libsldap/common/ns_config.c
index 2046a46bad..1a7a21bfee 100644
--- a/usr/src/lib/libsldap/common/ns_config.c
+++ b/usr/src/lib/libsldap/common/ns_config.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/*
* libsldap - library side configuration components
* Routines to manage the config structure
@@ -202,6 +200,12 @@ static ns_enum_map ns_pref_enum[] = {
{ -1, NULL },
};
+static ns_enum_map ns_shadow_update_enum[] = {
+ { ENUM2INT(NS_LDAP_ENABLE_SHADOW_UPDATE_FALSE), "FALSE" },
+ { ENUM2INT(NS_LDAP_ENABLE_SHADOW_UPDATE_TRUE), "TRUE" },
+ { -1, NULL },
+};
+
static int ns_def_auth_v1[] = {
ENUM2INT(NS_LDAP_EA_NONE),
0
@@ -392,11 +396,31 @@ static ns_default_config defconfig[] = {
NULL, /* not defined in the Profile */
{ CHARPTR, 0, NULL },
__s_val_binddn, NULL },
+
{"NS_LDAP_BINDPASSWD", NS_LDAP_BINDPASSWD_P,
CREDCONFIG, CHARPTR, TRUE, NS_LDAP_V2,
NULL, /* not defined in the Profile */
{ CHARPTR, 0, NULL },
__s_val_bindpw, NULL },
+
+ {"NS_LDAP_ENABLE_SHADOW_UPDATE", NS_LDAP_ENABLE_SHADOW_UPDATE_P,
+ CREDCONFIG, INT, TRUE, NS_LDAP_V2,
+ NULL, /* not defined in the Profile */
+ { INT, 0, INT2VOIDPTR(NS_LDAP_ENABLE_SHADOW_UPDATE_FALSE) },
+ NULL, ns_shadow_update_enum },
+
+ {"NS_LDAP_ADMIN_BINDDN", NS_LDAP_ADMIN_BINDDN_P,
+ CREDCONFIG, CHARPTR, TRUE, NS_LDAP_V2,
+ NULL, /* not defined in the Profile */
+ { CHARPTR, 0, NULL },
+ __s_val_binddn, NULL },
+
+ {"NS_LDAP_ADMIN_BINDPASSWD", NS_LDAP_ADMIN_BINDPASSWD_P,
+ CREDCONFIG, CHARPTR, TRUE, NS_LDAP_V2,
+ NULL, /* not defined in the Profile */
+ { CHARPTR, 0, NULL },
+ __s_val_bindpw, NULL },
+
{"NS_LDAP_EXP", NS_LDAP_EXP_P,
SERVERCONFIG, TIMET, TRUE, NS_LDAP_V2,
NULL, /* initialized by code to time+NS_LDAP_CACHETTL */
@@ -601,6 +625,9 @@ __s_get_enum_value(ns_config_t *ptr, char *value, ParamIndexType i)
case NS_LDAP_PREF_ONLY_P:
mapp = &ns_pref_enum[0];
break;
+ case NS_LDAP_ENABLE_SHADOW_UPDATE_P:
+ mapp = &ns_shadow_update_enum[0];
+ break;
case NS_LDAP_CREDENTIAL_LEVEL_P:
if (ptr->version == NS_LDAP_V1)
return (-1);
@@ -713,6 +740,21 @@ __s_get_searchref_name(ns_config_t *ptr, SearchRef_t type)
return ("Unknown SearchRef_t type specified");
}
+char *
+__s_get_shadowupdate_name(enableShadowUpdate_t type)
+{
+ register ns_enum_map *mapp;
+
+ mapp = &ns_shadow_update_enum[0];
+
+ for (; mapp->name != NULL; mapp++) {
+ if (type == INT2SHADOWUPDATENUM(mapp->value)) {
+ return (mapp->name);
+ }
+ }
+ return ("Unknown enableShadowUpdate_t type specified");
+}
+
static char *
__s_get_credlvl_name(ns_config_t *ptr, CredLevel_t type)
{
@@ -1486,6 +1528,8 @@ verify_value(ns_config_t *cfg, char *name, char *value, char *errstr)
case NS_LDAP_CERT_NICKNAME_P:
case NS_LDAP_BINDDN_P:
case NS_LDAP_BINDPASSWD_P:
+ case NS_LDAP_ADMIN_BINDDN_P:
+ case NS_LDAP_ADMIN_BINDPASSWD_P:
case NS_LDAP_DOMAIN_P:
case NS_LDAP_SEARCH_BASEDN_P:
case NS_LDAP_SEARCH_TIME_P:
@@ -1648,6 +1692,7 @@ __ns_ldap_setParamValue(ns_config_t *ptr, const ParamIndexType type,
case NS_LDAP_PREF_ONLY_P:
case NS_LDAP_SEARCH_REF_P:
case NS_LDAP_SEARCH_SCOPE_P:
+ case NS_LDAP_ENABLE_SHADOW_UPDATE_P:
i = __s_get_enum_value(ptr, cp, def->index);
if (i < 0) {
(void) snprintf(errstr, sizeof (errstr),
@@ -2615,7 +2660,8 @@ __ns_ldap_setParamValue(ns_config_t *ptr, const ParamIndexType type,
*
* Init NS_LDAP_EXP_P here when CACHETTL is updated
*/
- if (type == NS_LDAP_BINDPASSWD_P) {
+ if (type == NS_LDAP_BINDPASSWD_P ||
+ type == NS_LDAP_ADMIN_BINDPASSWD_P) {
cp = conf.ns_pc;
cp2 = evalue((char *)cp);
conf.ns_pc = cp2;
@@ -3219,6 +3265,11 @@ __s_api_strValue(ns_config_t *cfg, char *str,
__s_get_scope_name(cfg,
(ScopeType_t)ptr->ns_i));
break;
+ case NS_LDAP_ENABLE_SHADOW_UPDATE_P:
+ (void) strlcat(buf,
+ __s_get_shadowupdate_name(
+ (enableShadowUpdate_t)ptr->ns_i), bufsz);
+ break;
default:
(void) snprintf(ibuf, sizeof (ibuf),
"%d", ptr->ns_i);
@@ -3730,15 +3781,21 @@ static int
__s_val_binddn(ParamIndexType i, ns_default_config *def,
ns_param_t *param, char *errbuf)
{
+ char *dntype;
+
if (param && param->ns_ptype == CHARPTR &&
- i == NS_LDAP_BINDDN_P &&
+ (i == NS_LDAP_BINDDN_P || i == NS_LDAP_ADMIN_BINDDN_P) &&
((param->ns_pc == NULL) ||
((*(param->ns_pc) != '\0') &&
(strchr(param->ns_pc, '=') != NULL)))) {
return (NS_SUCCESS);
}
+ if (i == NS_LDAP_BINDDN_P)
+ dntype = "proxy";
+ else
+ dntype = "update";
(void) snprintf(errbuf, MAXERROR,
- gettext("NULL or invalid proxy bind DN"));
+ gettext("NULL or invalid %s bind DN"), dntype);
return (NS_PARSE_ERR);
}
@@ -3751,14 +3808,20 @@ static int
__s_val_bindpw(ParamIndexType i, ns_default_config *def,
ns_param_t *param, char *errbuf)
{
+ char *pwtype;
+
if (param && param->ns_ptype == CHARPTR &&
- i == NS_LDAP_BINDPASSWD_P &&
+ (i == NS_LDAP_BINDPASSWD_P || i == NS_LDAP_ADMIN_BINDPASSWD_P) &&
((param->ns_pc == NULL) ||
(*(param->ns_pc) != '\0'))) {
return (NS_SUCCESS);
}
+ if (i == NS_LDAP_BINDPASSWD_P)
+ pwtype = "proxy";
+ else
+ pwtype = "admin";
(void) snprintf(errbuf, MAXERROR,
- gettext("NULL proxy bind password"));
+ gettext("NULL %s bind password"), pwtype);
return (NS_PARSE_ERR);
}
diff --git a/usr/src/lib/libsldap/common/ns_confmgr.c b/usr/src/lib/libsldap/common/ns_confmgr.c
index 1fd58aac6f..a96f186ded 100644
--- a/usr/src/lib/libsldap/common/ns_confmgr.c
+++ b/usr/src/lib/libsldap/common/ns_confmgr.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
/* libsldap - cachemgr side configuration components */
#include <stdio.h>
@@ -332,6 +330,15 @@ __s_api_create_config_door_str(char *config, ns_ldap_error_t **errorp)
__s_api_destroy_config(configStruct);
return (NULL);
}
+ } else if (strcasecmp(attrVal,
+ _PROFILE1_OBJECTCLASS) == 0) {
+ if (__ns_ldap_setParamValue(configStruct,
+ NS_LDAP_FILE_VERSION_P,
+ NS_LDAP_VERSION_1,
+ errorp) != NS_LDAP_SUCCESS) {
+ __s_api_destroy_config(configStruct);
+ return (NULL);
+ }
}
continue;
}
@@ -490,6 +497,10 @@ __ns_ldap_LoadDoorInfo(LineBuf *configinfo, char *domainname, ns_config_t *new)
}
(void) memset((char *)configinfo, 0, sizeof (LineBuf));
for (i = 0; i <= NS_LDAP_MAX_PIT_P; i++) {
+ /* the credential for shadow update is not to be exposed */
+ if (i == NS_LDAP_ADMIN_BINDDN_P ||
+ i == NS_LDAP_ADMIN_BINDPASSWD_P)
+ continue;
str = __s_api_strValue(ptr, string, sizeof (string), i,
NS_DOOR_FMT);
if (str == NULL)
@@ -628,10 +639,15 @@ __ns_ldap_DumpLdif(char *filename)
if (str == NULL)
continue;
/*
- * don't dump binddn, bind password, or cert path as they
- * are not part of version 2 profiles
+ * don't dump binddn, bind password, admin binddn, admin
+ * bind password, enableShadowUpdate flag, or cert path
+ * as they are not part of version 2 profiles
*/
- if ((i != NS_LDAP_BINDDN_P) && (i != NS_LDAP_BINDPASSWD_P) &&
+ if ((i != NS_LDAP_BINDDN_P) &&
+ (i != NS_LDAP_BINDPASSWD_P) &&
+ (i != NS_LDAP_ADMIN_BINDDN_P) &&
+ (i != NS_LDAP_ADMIN_BINDPASSWD_P) &&
+ (i != NS_LDAP_ENABLE_SHADOW_UPDATE_P) &&
(i != NS_LDAP_HOST_CERTPATH_P))
(void) fprintf(fp, "%s\n", str);
if (str != (char *)&string[0]) {
@@ -922,6 +938,7 @@ __ns_ldap_make_config(ns_ldap_result_t *result)
}
}
if (ptr->version != NS_LDAP_V1) {
+ ParamIndexType i;
if (curr_ptr->paramList[NS_LDAP_BINDDN_P].ns_ptype == CHARPTR) {
(void) __ns_ldap_setParamValue(ptr, NS_LDAP_BINDDN_P,
curr_ptr->paramList[NS_LDAP_BINDDN_P].ns_pc,
@@ -934,6 +951,28 @@ __ns_ldap_make_config(ns_ldap_result_t *result)
curr_ptr->paramList[NS_LDAP_BINDPASSWD_P].ns_pc,
&error);
}
+ i = NS_LDAP_ENABLE_SHADOW_UPDATE_P;
+ if (curr_ptr->paramList[i].ns_ptype == INT) {
+ char *val;
+ val = __s_get_shadowupdate_name(
+ curr_ptr->paramList[i].ns_i);
+ (void) __ns_ldap_setParamValue(ptr, i, val, &error);
+ }
+ if (curr_ptr->paramList[NS_LDAP_ADMIN_BINDDN_P].ns_ptype ==
+ CHARPTR) {
+ (void) __ns_ldap_setParamValue(ptr,
+ NS_LDAP_ADMIN_BINDDN_P,
+ curr_ptr->paramList[NS_LDAP_ADMIN_BINDDN_P].ns_pc,
+ &error);
+ }
+ if (curr_ptr->paramList[NS_LDAP_ADMIN_BINDPASSWD_P].ns_ptype ==
+ CHARPTR) {
+ (void) __ns_ldap_setParamValue(ptr,
+ NS_LDAP_ADMIN_BINDPASSWD_P,
+ curr_ptr->
+ paramList[NS_LDAP_ADMIN_BINDPASSWD_P].ns_pc,
+ &error);
+ }
if (curr_ptr->paramList[NS_LDAP_HOST_CERTPATH_P].ns_ptype ==
CHARPTR) {
(void) __ns_ldap_setParamValue(ptr,
@@ -1065,6 +1104,11 @@ __ns_ldap_print_config(int verbose)
if ((i == NS_LDAP_CACHETTL_P) && (ptr->version == NS_LDAP_V1))
continue;
+ /* the credential for shadow update is not to be exposed */
+ if (i == NS_LDAP_ADMIN_BINDDN_P ||
+ i == NS_LDAP_ADMIN_BINDPASSWD_P)
+ continue;
+
str = __s_api_strValue(ptr, string, BUFSIZ, i, NS_FILE_FMT);
if (str == NULL)
continue;
diff --git a/usr/src/lib/libsldap/common/ns_internal.h b/usr/src/lib/libsldap/common/ns_internal.h
index a7dbf4e6de..9adba43565 100644
--- a/usr/src/lib/libsldap/common/ns_internal.h
+++ b/usr/src/lib/libsldap/common/ns_internal.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -27,8 +27,6 @@
#ifndef _NS_INTERNAL_H
#define _NS_INTERNAL_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -118,6 +116,11 @@ extern "C" {
/* max rdn length in conversion routines used by __ns_ldap_addTypedEntry() */
#define RDNSIZE 256
+/*
+ * special service used by ldap_cachemgr to indicate a shadow update
+ * is to be done with the credential of the administrator identity
+ */
+#define NS_ADMIN_SHADOW_UPDATE "shadow__admin_update"
/* Phase 1 profile information */
#define _PROFILE1_OBJECTCLASS "SolarisNamingProfile"
@@ -316,6 +319,7 @@ typedef struct ns_enum_map {
#define INT2SECENUM(x) ((TlsType_t)(x))
#define INT2PREFONLYENUM(x) ((PrefOnly_t)(x))
#define INT2CREDLEVELENUM(x) ((CredLevel_t)(x))
+#define INT2SHADOWUPDATENUM(x) ((enableShadowUpdate_t)(x))
#define INT2LDAPRETURN(x) ((ns_ldap_return_code)(x))
#define INT2CONFIGRETURN(x) ((ns_ldap_config_return_code)(x))
@@ -736,6 +740,7 @@ char *__s_get_security_name(ns_config_t *ptr, TlsType_t type);
char *__s_get_scope_name(ns_config_t *ptr, ScopeType_t type);
char *__s_get_pref_name(PrefOnly_t type);
char *__s_get_searchref_name(ns_config_t *ptr, SearchRef_t type);
+char *__s_get_shadowupdate_name(enableShadowUpdate_t type);
char *__s_get_hostcertpath(void);
void __s_api_free_sessionPool();
int __s_api_requestServer(const char *request, const char *server,
diff --git a/usr/src/lib/libsldap/common/ns_sldap.h b/usr/src/lib/libsldap/common/ns_sldap.h
index af288c5cf2..f8bb420019 100644
--- a/usr/src/lib/libsldap/common/ns_sldap.h
+++ b/usr/src/lib/libsldap/common/ns_sldap.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -84,6 +84,13 @@ typedef enum ScopeType {
#define NS_LDAP_NOT_CVT_DN 0x2000
/*
+ * NS_LDAP_UPDATE_SHADOW is for a privileged caller of the
+ * __ns_ldap_repAttr() to update the shadow database on the
+ * LDAP server.
+ */
+#define NS_LDAP_UPDATE_SHADOW 0x4000
+
+/*
* Authentication Information
*/
typedef enum CredLevel {
@@ -126,6 +133,11 @@ typedef enum PrefOnly {
NS_LDAP_PREF_TRUE = 1
} PrefOnly_t;
+typedef enum enableShadowUpdate {
+ NS_LDAP_ENABLE_SHADOW_UPDATE_FALSE = 0,
+ NS_LDAP_ENABLE_SHADOW_UPDATE_TRUE = 1
+} enableShadowUpdate_t;
+
typedef struct UnixCred {
char *userID; /* Unix ID number */
char *passwd; /* password */
@@ -199,12 +211,15 @@ typedef enum {
NS_LDAP_SERVICE_AUTH_METHOD_P = 25,
NS_LDAP_SERVICE_CRED_LEVEL_P = 26,
NS_LDAP_HOST_CERTPATH_P = 27,
+ NS_LDAP_ENABLE_SHADOW_UPDATE_P = 28,
+ NS_LDAP_ADMIN_BINDDN_P = 29,
+ NS_LDAP_ADMIN_BINDPASSWD_P = 30,
/*
* The following entry (max ParamIndexType) is an internal
* placeholder. It must be the last (and highest value)
* entry in this eNum. Please update accordingly.
*/
- NS_LDAP_MAX_PIT_P = 28
+ NS_LDAP_MAX_PIT_P = 31
} ParamIndexType;
@@ -484,6 +499,11 @@ typedef struct ns_ldap_objectclass_map {
char *mappedOC; /* mapped objectclass */
} ns_ldap_objectclass_map_t;
+/*
+ * Value of the userPassword attribute representing NO Unix password
+ */
+#define NS_LDAP_NO_UNIX_PASSWORD "<NO UNIX PASSWORD>"
+
/* Opaque handle for batch API */
typedef struct ns_ldap_list_batch ns_ldap_list_batch_t;
@@ -872,6 +892,9 @@ int __ns_ldap_getParamType(
int __ns_ldap_getAcctMgmt(
const char *user,
AcctUsableResponse_t *acctResp);
+
+boolean_t __ns_ldap_is_shadow_update_enabled();
+
void
__ns_ldap_self_gssapi_only_set(
int flag);
diff --git a/usr/src/lib/libsldap/common/ns_writes.c b/usr/src/lib/libsldap/common/ns_writes.c
index 3abbefd829..14727d8a6b 100644
--- a/usr/src/lib/libsldap/common/ns_writes.c
+++ b/usr/src/lib/libsldap/common/ns_writes.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
@@ -38,10 +36,13 @@
#include <lber.h>
#include <ldap.h>
#include <syslog.h>
+#include <stddef.h>
+#include <sys/mman.h>
#include "ns_sldap.h"
#include "ns_internal.h"
#include "ns_connmgmt.h"
+#include "ns_cache_door.h"
/* Additional headers for addTypedEntry Conversion routines */
#include <pwd.h>
@@ -60,7 +61,8 @@
#include <sys/tsol/tndb.h>
#include <tsol/label.h>
-
+static int send_to_cachemgr(const char *,
+ ns_ldap_attr_t **, ns_ldap_error_t **);
/*
* If the rdn is a mapped attr:
* return NS_LDAP_SUCCESS and a new_dn.
@@ -1038,8 +1040,8 @@ write_state_machine(
errmsg = NULL;
}
- (void) sprintf(errstr,
- gettext(ldap_err2string(Errno)));
+ (void) snprintf(errstr, sizeof (errstr),
+ "%s", ldap_err2string(Errno));
err = strdup(errstr);
if (pwd_status != NS_PASSWD_GOOD) {
MKERROR_PWD_MGMT(*errorp, Errno, err,
@@ -1157,6 +1159,89 @@ __ns_ldap_delAttr(
return (rc);
}
+/* Retrieve the admin bind password from the configuration, if allowed. */
+static int
+get_admin_passwd(ns_cred_t *cred, ns_ldap_error_t **errorp)
+{
+ void **paramVal = NULL;
+ int rc, ldaprc;
+ char *modparamVal = NULL;
+
+ /*
+ * For GSSAPI/Kerberos, host credential is used, no need to get
+ * admin bind password
+ */
+ if (cred->auth.saslmech == NS_LDAP_SASL_GSSAPI)
+ return (NS_LDAP_SUCCESS);
+
+ /*
+ * Retrieve admin bind password.
+ * The admin bind password is available
+ * only in the ldap_cachemgr process as
+ * they are not exposed outside of that
+ * process.
+ */
+ paramVal = NULL;
+ if ((ldaprc = __ns_ldap_getParam(NS_LDAP_ADMIN_BINDPASSWD_P,
+ &paramVal, errorp)) != NS_LDAP_SUCCESS)
+ return (ldaprc);
+ if (paramVal == NULL || *paramVal == NULL) {
+ rc = NS_LDAP_CONFIG;
+ *errorp = __s_api_make_error(NS_CONFIG_NODEFAULT,
+ gettext("Admin bind password not configured"));
+ if (*errorp == NULL)
+ rc = NS_LDAP_MEMORY;
+ return (rc);
+ }
+ modparamVal = dvalue((char *)*paramVal);
+ (void) memset(*paramVal, 0, strlen((char *)*paramVal));
+ (void) __ns_ldap_freeParam(&paramVal);
+ if (modparamVal == NULL || *((char *)modparamVal) == '\0') {
+ if (modparamVal != NULL)
+ free(modparamVal);
+ rc = NS_LDAP_CONFIG;
+ *errorp = __s_api_make_error(NS_CONFIG_SYNTAX,
+ gettext("bind password not valid"));
+ if (*errorp == NULL)
+ rc = NS_LDAP_MEMORY;
+ return (rc);
+ }
+
+ cred->cred.unix_cred.passwd = modparamVal;
+ return (NS_LDAP_SUCCESS);
+}
+
+boolean_t
+__ns_ldap_is_shadow_update_enabled() {
+
+ int **enable_shadow = NULL;
+
+ if (__ns_ldap_getParam(NS_LDAP_ENABLE_SHADOW_UPDATE_P,
+ (void ***)&enable_shadow, NULL) != NS_LDAP_SUCCESS) {
+ return (B_FALSE);
+ }
+ if ((enable_shadow != NULL && *enable_shadow != NULL) &&
+ (*enable_shadow[0] == NS_LDAP_ENABLE_SHADOW_UPDATE_TRUE)) {
+ (void) __ns_ldap_freeParam((void ***)&enable_shadow);
+ return (B_TRUE);
+ }
+ if (enable_shadow != NULL)
+ (void) __ns_ldap_freeParam((void ***)&enable_shadow);
+ return (B_FALSE);
+}
+
+/*
+ * __ns_ldap_repAttr modifies ldap attributes of the 'dn' entry stored
+ * on the LDAP server. 'service' indicates the type of database entries
+ * to modify. When the Native LDAP client is configured with 'shadow update
+ * enabled', Shadowshadow(4) entries can only be modified by privileged users.
+ * Such users use the NS_LDAP_UPDATE_SHADOW flag to indicate the call is
+ * for such a shadow(4) update, which would be forwarded to ldap_cachemgr
+ * for performing the LDAP modify operation. ldap_cachemgr would call
+ * this function again and use the special service NS_ADMIN_SHADOW_UPDATE
+ * to identify itself, so that admin credential would be obtained and
+ * the actual LDAP modify operation be done.
+ */
/*ARGSUSED*/
int
__ns_ldap_repAttr(
@@ -1169,6 +1254,8 @@ __ns_ldap_repAttr(
{
LDAPMod **mods;
int rc = 0;
+ boolean_t priv;
+ boolean_t shadow_update_enabled = B_FALSE;
#ifdef DEBUG
(void) fprintf(stderr, "__ns_ldap_repAttr START\n");
@@ -1176,13 +1263,59 @@ __ns_ldap_repAttr(
*errorp = NULL;
/* Sanity check */
- if ((attr == NULL) || (*attr == NULL) ||
- (dn == NULL) || (cred == NULL))
+ if (attr == NULL || *attr == NULL || dn == NULL)
+ return (NS_LDAP_INVALID_PARAM);
+
+ /* Privileged shadow modify? */
+ if ((flags & NS_LDAP_UPDATE_SHADOW) != 0 &&
+ strcmp(service, "shadow") == 0) {
+
+ /* Shadow update enabled ? If not, error out */
+ shadow_update_enabled = __ns_ldap_is_shadow_update_enabled();
+ if (!shadow_update_enabled) {
+ *errorp = __s_api_make_error(NS_CONFIG_NOTALLOW,
+ gettext("Shadow Update is not enabled"));
+ return (NS_LDAP_CONFIG);
+ }
+
+ /* privileged shadow modify requires euid 0 or all zone privs */
+ priv = (geteuid() == 0);
+ if (!priv) {
+ priv_set_t *ps = priv_allocset(); /* caller */
+ priv_set_t *zs; /* zone */
+
+ (void) getppriv(PRIV_EFFECTIVE, ps);
+ zs = priv_str_to_set("zone", ",", NULL);
+ priv = priv_isequalset(ps, zs);
+ priv_freeset(ps);
+ priv_freeset(zs);
+ }
+ if (!priv)
+ return (NS_LDAP_OP_FAILED);
+
+ rc = send_to_cachemgr(dn, (ns_ldap_attr_t **)attr, errorp);
+ return (rc);
+ }
+
+ if (cred == NULL)
return (NS_LDAP_INVALID_PARAM);
+
+ /*
+ * If service is NS_ADMIN_SHADOW_UPDATE, the caller should be
+ * ldap_cachemgr. We need to get the admin cred to do work.
+ * If the caller is not ldap_cachemgr, but use the service
+ * NS_ADMIN_SHADOW_UPDATE, get_admin_passwd() will fail,
+ * as the admin cred is not available to the caller.
+ */
+ if (strcmp(service, NS_ADMIN_SHADOW_UPDATE) == 0) {
+ if ((rc = get_admin_passwd((ns_cred_t *)cred, errorp)) !=
+ NS_LDAP_SUCCESS)
+ return (rc);
+ }
+
mods = __s_api_makeModList(service, attr, LDAP_MOD_REPLACE, flags);
- if (mods == NULL) {
+ if (mods == NULL)
return (NS_LDAP_MEMORY);
- }
rc = write_state_machine(LDAP_REQ_MODIFY,
(char *)dn, mods, cred, flags, errorp);
@@ -1191,7 +1324,6 @@ __ns_ldap_repAttr(
return (rc);
}
-
/*ARGSUSED*/
int
__ns_ldap_addEntry(
@@ -3793,3 +3925,157 @@ __s_api_append_default_basedn(
(void) __ns_ldap_freeParam(&param);
return (NS_LDAP_SUCCESS);
}
+
+/*
+ * Flatten the input ns_ldap_attr_t list, 'attr', and convert it into an
+ * ldap_strlist_t structure in buffer 'buf', to be used by ldap_cachemgr.
+ * The output contains a count, a list of offsets, which show where the
+ * corresponding copied attribute type and attribute value are located.
+ * For example, for dn=aaaa, userpassword=bbbb, shadowlastchange=cccc,
+ * the output is the ldap_strlist_t structure with: ldap_count = 6,
+ * (buf + ldap_offsets[0]) -> "dn"
+ * (buf + ldap_offsets[1]) -> "aaaa"
+ * (buf + ldap_offsets[2]) -> "userPassword"
+ * (buf + ldap_offsets[3]) -> "bbbb"
+ * (buf + ldap_offsets[4]) -> "shadowlastchange"
+ * (buf + ldap_offsets[5]) -> "cccc"
+ * and all the string data shown above copied into the buffer after
+ * the offset array. The total length of the data will be the return
+ * value, or -1 if error.
+ */
+static int
+attr2list(const char *dn, ns_ldap_attr_t **attr,
+ char *buf, int bufsize)
+{
+ int c = 0;
+ char *ap;
+ int ao;
+ ldap_strlist_t *al = (ldap_strlist_t *)buf;
+ ns_ldap_attr_t *a = (ns_ldap_attr_t *)*attr;
+ ns_ldap_attr_t **aptr = (ns_ldap_attr_t **)attr;
+
+ /* bufsize > strlen(dn) + strlen("dn") + 1 ('\0') */
+ if ((strlen(dn) + 2 + 1) >= bufsize)
+ return (-1);
+
+ /* count number of attributes */
+ while (*aptr++)
+ c++;
+ al->ldap_count = 2 + c * 2;
+ ao = sizeof (al->ldap_count) + sizeof (al->ldap_offsets[0]) *
+ al->ldap_count;
+ if (ao > bufsize)
+ return (-1);
+ al->ldap_offsets[0] = ao;
+ ap = buf + ao;
+ ao += 3;
+
+ /* copy entry DN */
+ if (ao > bufsize)
+ return (-1);
+ (void) strlcpy(ap, "dn", bufsize);
+ ap += 3;
+
+ al->ldap_offsets[1] = ao;
+ ao += strlen(dn) + 1;
+ if (ao > bufsize)
+ return (-1);
+ (void) strlcpy(ap, dn, bufsize);
+ ap = buf + ao;
+
+ aptr = attr;
+ for (c = 2; c < al->ldap_count; c++, aptr++) {
+ a = *aptr;
+ if (a->attrname == NULL || a->attrvalue == NULL ||
+ a->value_count != 1 || a->attrvalue[0] == NULL)
+ return (-1);
+ al->ldap_offsets[c] = ao;
+ ao += strlen(a->attrname) + 1;
+ if (ao > bufsize)
+ return (-1);
+ (void) strlcpy(ap, a->attrname, bufsize);
+ ap = buf + ao;
+
+ c++;
+ al->ldap_offsets[c] = ao;
+ ao += strlen(a->attrvalue[0]) + 1;
+ (void) strlcpy(ap, a->attrvalue[0], bufsize);
+ ap = buf + ao;
+ };
+
+ return (ao);
+}
+
+/*
+ * Send a modify request to the ldap_cachemgr daemon
+ * which will use the admin credential to perform the
+ * operation.
+ */
+
+static int
+send_to_cachemgr(
+ const char *dn,
+ ns_ldap_attr_t **attr,
+ ns_ldap_error_t **errorp)
+{
+ union {
+ ldap_data_t s_d;
+ char s_b[DOORBUFFERSIZE];
+ } space;
+
+ ldap_data_t *sptr;
+ int ndata;
+ int adata;
+ int len;
+ int rc;
+ char errstr[MAXERROR];
+ ldap_admin_mod_result_t *admin_result;
+
+ *errorp = NULL;
+ (void) memset(space.s_b, 0, DOORBUFFERSIZE);
+ len = attr2list(dn, attr, (char *)&space.s_d.ldap_call.ldap_u.strlist,
+ sizeof (space) - offsetof(ldap_return_t, ldap_u));
+ if (len <= 0)
+ return (NS_LDAP_INVALID_PARAM);
+
+ adata = sizeof (ldap_call_t) + len;
+ ndata = sizeof (space);
+ space.s_d.ldap_call.ldap_callnumber = ADMINMODIFY;
+ sptr = &space.s_d;
+
+ switch (__ns_ldap_trydoorcall(&sptr, &ndata, &adata)) {
+ case NS_CACHE_SUCCESS:
+ break;
+ case NS_CACHE_NOTFOUND:
+ (void) snprintf(errstr, sizeof (errstr),
+ gettext("Door call ADMINMODIFY to "
+ "ldap_cachemgr failed - error: %d"),
+ space.s_d.ldap_ret.ldap_errno);
+ MKERROR(LOG_WARNING, *errorp, NS_CONFIG_CACHEMGR,
+ strdup(errstr), NULL);
+ return (NS_LDAP_OP_FAILED);
+ break;
+ default:
+ return (NS_LDAP_OP_FAILED);
+ }
+
+ admin_result = &sptr->ldap_ret.ldap_u.admin_result;
+ if (admin_result->ns_err == NS_LDAP_SUCCESS)
+ rc = NS_LDAP_SUCCESS;
+ else {
+ rc = admin_result->ns_err;
+ if (admin_result->msg_size == 0)
+ *errorp = __s_api_make_error(admin_result->status,
+ NULL);
+ else
+ *errorp = __s_api_make_error(admin_result->status,
+ admin_result->msg);
+ }
+
+ /* clean up the door call */
+ if (sptr != &space.s_d) {
+ (void) munmap((char *)sptr, ndata);
+ }
+
+ return (rc);
+}
diff --git a/usr/src/lib/nsswitch/ldap/common/getspent.c b/usr/src/lib/nsswitch/ldap/common/getspent.c
index a533300a08..bcdba2998c 100644
--- a/usr/src/lib/nsswitch/ldap/common/getspent.c
+++ b/usr/src/lib/nsswitch/ldap/common/getspent.c
@@ -19,11 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-
#include <shadow.h>
#include <stdlib.h>
#include "ldap_common.h"
@@ -31,6 +30,12 @@
/* shadow attributes filters */
#define _S_UID "uid"
#define _S_USERPASSWORD "userpassword"
+#define _S_LASTCHANGE "shadowlastchange"
+#define _S_MIN "shadowmin"
+#define _S_MAX "shadowmax"
+#define _S_WARNING "shadowwarning"
+#define _S_INACTIVE "shadowinactive"
+#define _S_EXPIRE "shadowexpire"
#define _S_FLAG "shadowflag"
#define _F_GETSPNAM "(&(objectClass=shadowAccount)(uid=%s))"
@@ -39,6 +44,12 @@
static const char *sp_attrs[] = {
_S_UID,
_S_USERPASSWORD,
+ _S_LASTCHANGE,
+ _S_MIN,
+ _S_MAX,
+ _S_WARNING,
+ _S_INACTIVE,
+ _S_EXPIRE,
_S_FLAG,
(char *)NULL
};
@@ -59,11 +70,15 @@ _nss_ldap_shadow2str(ldap_backend_ptr be, nss_XbyY_args_t *argp)
{
int nss_result;
int buflen = 0;
+ int shadow_update_enabled;
unsigned long len = 0L;
char *tmp, *buffer = NULL;
char *pw_passwd = NULL;
ns_ldap_result_t *result = be->result;
- char **uid, **passwd, **flag, *flag_str;
+ char **uid, **passwd, **last, **smin, **smax;
+ char **warning, **inactive, **expire, **flag;
+ char *last_str, *min_str, *max_str, *warning_str;
+ char *inactive_str, *expire_str, *flag_str;
if (result == NULL)
return (NSS_STR_PARSE_PARSE);
@@ -94,11 +109,15 @@ _nss_ldap_shadow2str(ldap_backend_ptr be, nss_XbyY_args_t *argp)
goto result_spd2str;
} else {
if ((tmp = strstr(passwd[0], "{crypt}")) != NULL ||
- (tmp = strstr(passwd[0], "{CRYPT}")) != NULL) {
+ (tmp = strstr(passwd[0], "{CRYPT}")) != NULL) {
if (tmp != passwd[0])
pw_passwd = NOPWDRTR;
- else
+ else {
pw_passwd = tmp + strlen("{crypt}");
+ if (strcmp(pw_passwd,
+ NS_LDAP_NO_UNIX_PASSWORD) == 0)
+ *pw_passwd = '\0';
+ }
} else {
/* mark password as not retrievable */
pw_passwd = NOPWDRTR;
@@ -107,19 +126,66 @@ _nss_ldap_shadow2str(ldap_backend_ptr be, nss_XbyY_args_t *argp)
len += strlen(pw_passwd);
/*
- * Ignore the following password aging related attributes:
+ * If shadow update is not enabled, ignore the following
+ * password aging related attributes:
* -- shadowlastchange
* -- shadowmin
* -- shadowmax
* -- shadowwarning
* -- shadowinactive
* -- shadowexpire
- * This is because the LDAP naming service does not
- * really support the password aging fields defined
- * in the shadow structure. These fields, sp_lstchg,
+ * When shadow update is not enabled, the LDAP naming
+ * service does not support the password aging fields
+ * defined in the shadow structure. These fields, sp_lstchg,
* sp_min, sp_max, sp_warn, sp_inact, and sp_expire,
* will be set to -1 by the front end marshaller.
*/
+
+ shadow_update_enabled = __ns_ldap_is_shadow_update_enabled();
+ if (shadow_update_enabled) {
+ last = __ns_ldap_getAttr(result->entry, _S_LASTCHANGE);
+ if (last == NULL || last[0] == NULL)
+ last_str = _NO_VALUE;
+ else
+ last_str = last[0];
+ len += strlen(last_str);
+
+ smin = __ns_ldap_getAttr(result->entry, _S_MIN);
+ if (smin == NULL || smin[0] == NULL)
+ min_str = _NO_VALUE;
+ else
+ min_str = smin[0];
+ len += strlen(min_str);
+
+ smax = __ns_ldap_getAttr(result->entry, _S_MAX);
+ if (smax == NULL || smax[0] == NULL)
+ max_str = _NO_VALUE;
+ else
+ max_str = smax[0];
+ len += strlen(max_str);
+
+ warning = __ns_ldap_getAttr(result->entry, _S_WARNING);
+ if (warning == NULL || warning[0] == NULL)
+ warning_str = _NO_VALUE;
+ else
+ warning_str = warning[0];
+ len += strlen(warning_str);
+
+ inactive = __ns_ldap_getAttr(result->entry, _S_INACTIVE);
+ if (inactive == NULL || inactive[0] == NULL)
+ inactive_str = _NO_VALUE;
+ else
+ inactive_str = inactive[0];
+ len += strlen(inactive_str);
+
+ expire = __ns_ldap_getAttr(result->entry, _S_EXPIRE);
+ if (expire == NULL || expire[0] == NULL)
+ expire_str = _NO_VALUE;
+ else
+ expire_str = expire[0];
+ len += strlen(expire_str);
+ }
+
flag = __ns_ldap_getAttr(result->entry, _S_FLAG);
if (flag == NULL || flag[0] == NULL)
flag_str = _NO_VALUE;
@@ -144,8 +210,14 @@ _nss_ldap_shadow2str(ldap_backend_ptr be, nss_XbyY_args_t *argp)
} else
buffer = argp->buf.buffer;
- (void) snprintf(buffer, len, "%s:%s:::::::%s",
- uid[0], pw_passwd, flag_str);
+ if (shadow_update_enabled) {
+ (void) snprintf(buffer, len, "%s:%s:%s:%s:%s:%s:%s:%s:%s",
+ uid[0], pw_passwd, last_str, min_str, max_str, warning_str,
+ inactive_str, expire_str, flag_str);
+ } else {
+ (void) snprintf(buffer, len, "%s:%s:::::::%s",
+ uid[0], pw_passwd, flag_str);
+ }
/* The front end marhsaller doesn't need the trailing null */
if (argp->buf.result != NULL)
@@ -185,7 +257,7 @@ getbynam(ldap_backend_ptr be, void *a)
return ((nss_status_t)NSS_NOTFOUND);
return (_nss_ldap_lookup(be, argp, _SHADOW, searchfilter, NULL,
- _merge_SSD_filter, userdata));
+ _merge_SSD_filter, userdata));
}
static ldap_backend_op_t sp_ops[] = {
@@ -210,6 +282,6 @@ _nss_ldap_shadow_constr(const char *dummy1, const char *dummy2,
{
return ((nss_backend_t *)_nss_ldap_constr(sp_ops,
- sizeof (sp_ops)/sizeof (sp_ops[0]),
- _SHADOW, sp_attrs, _nss_ldap_shadow2str));
+ sizeof (sp_ops)/sizeof (sp_ops[0]),
+ _SHADOW, sp_attrs, _nss_ldap_shadow2str));
}
diff --git a/usr/src/lib/passwdutil/__failed_count.c b/usr/src/lib/passwdutil/__failed_count.c
index 777408d3b5..a72a2fba26 100644
--- a/usr/src/lib/passwdutil/__failed_count.c
+++ b/usr/src/lib/passwdutil/__failed_count.c
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <string.h>
#include <syslog.h>
#include "passwdutil.h"
@@ -35,23 +33,31 @@ __incr_failed_count(char *username, char *repname, int max_failures)
int ret;
void *buf;
attrlist items[1];
- repops_t *ops = rops[REP_FILES];
+ int repnum = name_to_int(repname);
+ repops_t *ops;
- /* account locking only defined for files */
- if (strcmp(repname, "files") != 0)
+ /* account locking only defined for files and ldap */
+ if ((repnum != REP_FILES) &&
+ (repnum != REP_LDAP)) {
return (PWU_SUCCESS);
+ }
- if ((ret = ops->lock()) != PWU_SUCCESS)
+ ops = rops[repnum];
+ if ((ops->lock != NULL) &&
+ (ret = ops->lock()) != PWU_SUCCESS) {
return (ret);
+ }
items[0].type = ATTR_INCR_FAILED_LOGINS;
items[0].next = NULL;
- if ((ret = ops->getpwnam(username, items, NULL, &buf)) != PWU_SUCCESS)
+ if ((ret = ops->getpwnam(username, items, NULL, &buf)) != PWU_SUCCESS) {
goto out;
+ }
/* We increment the failed count by one */
- if ((ret = ops->update(items, NULL, buf)) != PWU_SUCCESS)
+ if ((ret = ops->update(items, NULL, buf)) != PWU_SUCCESS) {
goto out;
+ }
/* Did we just exceed "max_failures" ? */
if (items[0].data.val_i >= max_failures) {
@@ -69,7 +75,9 @@ __incr_failed_count(char *username, char *repname, int max_failures)
ret = PWU_ACCOUNT_LOCKED;
out:
- ops->unlock();
+ if (ops->unlock != NULL) {
+ ops->unlock();
+ }
return (ret);
}
@@ -84,14 +92,20 @@ __rst_failed_count(char *username, char *repname)
int ret;
void *buf;
attrlist items[1];
- repops_t *ops = rops[REP_FILES];
+ int repnum = name_to_int(repname);
+ repops_t *ops;
- /* account locking only defined for files */
- if (strcmp(repname, "files") != 0)
+ /* account locking only defined for files and ldap */
+ if ((repnum != REP_FILES) &&
+ (repnum != REP_LDAP)) {
return (PWU_SUCCESS);
+ }
- if ((ret = ops->lock()) != PWU_SUCCESS)
+ ops = rops[repnum];
+ if ((ops->lock != NULL) &&
+ (ret = ops->lock()) != PWU_SUCCESS) {
return (ret);
+ }
items[0].type = ATTR_RST_FAILED_LOGINS;
items[0].next = NULL;
@@ -101,7 +115,9 @@ __rst_failed_count(char *username, char *repname)
goto out;
ret = ops->putpwnam(username, NULL, NULL, NULL, buf);
out:
- ops->unlock();
+ if (ops->unlock != NULL) {
+ ops->unlock();
+ }
return (ret != PWU_SUCCESS ? ret : items[0].data.val_i);
}
diff --git a/usr/src/lib/passwdutil/ldap_attr.c b/usr/src/lib/passwdutil/ldap_attr.c
index 7cf40be7a1..7a29614bf3 100644
--- a/usr/src/lib/passwdutil/ldap_attr.c
+++ b/usr/src/lib/passwdutil/ldap_attr.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,17 +19,17 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <macros.h>
+#include <priv.h>
#include "ns_sldap.h"
@@ -45,6 +44,32 @@
#include "utils.h"
+#define MAX_INT_LEN 11 /* 10+1 %d buflen for words/ints [not longs] */
+
+#define STRDUP_OR_RET(to, from) \
+ if ((to = strdup(from)) == NULL) \
+ return (PWU_NOMEM);
+
+#define STRDUP_OR_ERR(to, from, err) \
+ if (((to) = strdup(from)) == NULL) \
+ (err) = PWU_NOMEM;
+
+#define NUM_TO_STR(to, from) \
+ { \
+ char nb[MAX_INT_LEN]; \
+ if (snprintf(nb, MAX_INT_LEN, "%d", (from)) >= MAX_INT_LEN) \
+ return (PWU_NOMEM); \
+ STRDUP_OR_RET(to, nb); \
+ }
+
+#define NEW_ATTR(p, i, attr, val) \
+ { \
+ p[i] = new_attr(attr, (val)); \
+ if (p[i] == NULL) \
+ return (PWU_NOMEM); \
+ i++; \
+ }
+
int ldap_getattr(char *name, attrlist *item, pwu_repository_t *rep);
int ldap_getpwnam(char *name, attrlist *items, pwu_repository_t *rep,
void **buf);
@@ -73,9 +98,14 @@ struct repops ldap_repops = {
* structure used to keep state between get/update/put calls
*/
typedef struct {
- char *passwd; /* encrypted password */
+ char *passwd; /* encrypted password */
struct passwd *pwd;
- ns_ldap_attr_t **attrs;
+ ns_ldap_attr_t **pattrs; /* passwd attrs */
+ int npattrs; /* max attrs */
+ struct spwd *spwd;
+ ns_ldap_attr_t **sattrs; /* passwd attrs */
+ int nsattrs; /* max attrs */
+ boolean_t shadow_update_enabled; /* shadow update configured */
} ldapbuf_t;
/*
@@ -94,15 +124,70 @@ typedef struct {
#define _PWD_HOMEDIRECTORY "homedirectory"
#define _PWD_LOGINSHELL "loginshell"
+#define _PWD_MAX_ATTR 10 /* 9+NULL */
+
+/* shadow attributes filters */
+#define _S_LASTCHANGE "shadowlastchange"
+#define _S_MIN "shadowmin"
+#define _S_MAX "shadowmax"
+#define _S_WARNING "shadowwarning"
+#define _S_INACTIVE "shadowinactive"
+#define _S_EXPIRE "shadowexpire"
+#define _S_FLAG "shadowflag"
+
+#define _S_MAX_ATTR 8 /* 7+NULL */
+
+/*
+ * Frees up an ldapbuf_t
+ */
+
+static void
+free_ldapbuf(ldapbuf_t *p)
+{
+ int i;
+
+ if (p == NULL)
+ return;
+ if (p->passwd) {
+ (void) memset(p->passwd, 0, strlen(p->passwd));
+ free(p->passwd);
+ }
+ if (p->pwd)
+ free_pwd(p->pwd);
+ if (p->spwd)
+ free_spwd(p->spwd);
+ if (p->pattrs) {
+ for (i = 0; i < p->npattrs; i++) {
+ if (p->pattrs[i] != NULL) {
+ free(p->pattrs[i]->attrvalue[0]);
+ free(p->pattrs[i]);
+ }
+ }
+ free(p->pattrs);
+ }
+ if (p->sattrs) {
+ for (i = 0; i < p->nsattrs; i++) {
+ if (p->sattrs[i] != NULL) {
+ free(p->sattrs[i]->attrvalue[0]);
+ free(p->sattrs[i]);
+ }
+ }
+ free(p->sattrs);
+ }
+}
+
/*
* int ldap_user_to_authenticate(user, rep, auth_user, privileged)
*
- * We can't determine whether the user is "privileged" in the LDAP
- * sense. The operation should be attempted and will succeed if
- * the user had privileges.
- *
- * For our purposes, we say that the user is privileged if he/she
- * is attempting to change another user's password attributes.
+ * If the Shadow Update functionality is enabled, then we check to
+ * see if the caller has 0 as the euid or has all zone privs. If so,
+ * the caller would be able to modify shadow(4) data stored on the
+ * LDAP server. Otherwise, when LDAP Shadow Update is not enabled,
+ * we can't determine whether the user is "privileged" in the LDAP
+ * sense. The operation should be attempted and will succeed if the
+ * user had privileges. For our purposes, we say that the user is
+ * privileged if he/she is attempting to change another user's
+ * password attributes.
*/
int
ldap_user_to_authenticate(char *user, pwu_repository_t *rep,
@@ -121,11 +206,47 @@ ldap_user_to_authenticate(char *user, pwu_repository_t *rep,
uid = getuid();
+ /*
+ * need equivalent of write access to /etc/shadow
+ * the privilege escalation model is euid == 0 || all zone privs
+ */
+ if (__ns_ldap_is_shadow_update_enabled()) {
+ boolean_t priv;
+
+ priv = (geteuid() == 0);
+ if (!priv) {
+ priv_set_t *ps = priv_allocset(); /* caller */
+ priv_set_t *zs; /* zone */
+
+ (void) getppriv(PRIV_EFFECTIVE, ps);
+ zs = priv_str_to_set("zone", ",", NULL);
+ priv = priv_isequalset(ps, zs);
+ priv_freeset(ps);
+ priv_freeset(zs);
+ }
+ /*
+ * priv can change anyone's password,
+ * only root isn't prompted.
+ */
+ *privileged = 0; /* for proper prompting */
+ if (priv) {
+ if (uid == 0) {
+ *privileged = 1;
+ *auth_user = NULL;
+ return (res);
+ } else if (uid == pw->pw_uid) {
+ STRDUP_OR_ERR(*auth_user, user, res);
+ return (res);
+ }
+ }
+
+ return (PWU_DENIED);
+ }
+
if (uid == pw->pw_uid) {
- /* changing out own, not privileged */
+ /* changing our own, not privileged */
*privileged = 0;
- if ((*auth_user = strdup(user)) == NULL)
- res = PWU_NOMEM;
+ STRDUP_OR_RET(*auth_user, user);
} else {
char pwd_buf[1024];
struct passwd pwr;
@@ -141,17 +262,15 @@ ldap_user_to_authenticate(char *user, pwu_repository_t *rep,
priviledged_uid = uid;
}
if (getpwuid_r(priviledged_uid, &pwr, pwd_buf,
- sizeof (pwd_buf)) != NULL) {
- if ((*auth_user = strdup(pwr.pw_name)) == NULL)
- res = PWU_NOMEM;
+ sizeof (pwd_buf)) != NULL) {
+ STRDUP_OR_ERR(*auth_user, pwr.pw_name, res);
} else {
/* hmm. can't find name of current user...??? */
-#define MAX_UID_LEN 11 /* UID's larger than 2^32 won't fit... */
- if ((*auth_user = malloc(MAX_UID_LEN)) == NULL) {
+ if ((*auth_user = malloc(MAX_INT_LEN)) == NULL) {
res = PWU_NOMEM;
} else {
- (void) snprintf(*auth_user, MAX_UID_LEN, "%d",
+ (void) snprintf(*auth_user, MAX_INT_LEN, "%d",
(int)uid);
}
}
@@ -169,70 +288,45 @@ ldap_user_to_authenticate(char *user, pwu_repository_t *rep,
int
ldap_getattr(char *name, attrlist *items, pwu_repository_t *rep)
{
+ attrlist *w;
int res;
+ ldapbuf_t *ldapbuf;
struct passwd *pw = NULL;
struct spwd *spw = NULL;
- attrlist *w;
- int need_shadow = 0; /* Need shadow info from LDAP server */
- int need_normal = 0; /* Need non-shadow info from LDAP server */
+ res = ldap_getpwnam(name, items, rep, (void **)&ldapbuf);
+ if (res != PWU_SUCCESS)
+ return (res);
- /* We need the "shadow" map for the password only */
- for (w = items; w != NULL; w = w->next) {
- if (w->type == ATTR_PASSWD ||
- w->type == ATTR_PASSWD_SERVER_POLICY)
- need_shadow = 1;
- else
- need_normal = 1;
- }
-
- if (need_normal) {
- res = dup_pw(&pw, getpwnam_from(name, rep, REP_LDAP));
- if (res != PWU_SUCCESS)
- goto out;
- }
-
- if (need_shadow) {
- res = dup_spw(&spw, getspnam_from(name, rep, REP_LDAP));
- if (res != PWU_SUCCESS) {
- goto out;
- }
- }
+ pw = ldapbuf->pwd;
+ spw = ldapbuf->spwd;
for (w = items; res == PWU_SUCCESS && w != NULL; w = w->next) {
switch (w->type) {
case ATTR_NAME:
- if ((w->data.val_s = strdup(pw->pw_name)) == NULL)
- res = PWU_NOMEM;
+ STRDUP_OR_ERR(w->data.val_s, pw->pw_name, res);
break;
case ATTR_COMMENT:
- if ((w->data.val_s = strdup(pw->pw_comment)) == NULL)
- res = PWU_NOMEM;
+ STRDUP_OR_ERR(w->data.val_s, pw->pw_comment, res);
break;
case ATTR_GECOS:
- if ((w->data.val_s = strdup(pw->pw_gecos)) == NULL)
- res = PWU_NOMEM;
+ STRDUP_OR_ERR(w->data.val_s, pw->pw_gecos, res);
break;
case ATTR_HOMEDIR:
- if ((w->data.val_s = strdup(pw->pw_dir)) == NULL)
- res = PWU_NOMEM;
+ STRDUP_OR_ERR(w->data.val_s, pw->pw_dir, res);
break;
case ATTR_SHELL:
- if ((w->data.val_s = strdup(pw->pw_shell)) == NULL)
- res = PWU_NOMEM;
+ STRDUP_OR_ERR(w->data.val_s, pw->pw_shell, res);
break;
case ATTR_PASSWD:
case ATTR_PASSWD_SERVER_POLICY:
- if ((w->data.val_s = strdup(spw->sp_pwdp)) == NULL)
- res = PWU_NOMEM;
+ STRDUP_OR_ERR(w->data.val_s, spw->sp_pwdp, res);
break;
case ATTR_AGE:
- if ((w->data.val_s = strdup(pw->pw_age)) == NULL)
- res = PWU_NOMEM;
+ STRDUP_OR_ERR(w->data.val_s, pw->pw_age, res);
break;
case ATTR_REP_NAME:
- if ((w->data.val_s = strdup("ldap")) == NULL)
- res = PWU_NOMEM;
+ STRDUP_OR_ERR(w->data.val_s, "ldap", res);
break;
/* integer values */
@@ -243,24 +337,47 @@ ldap_getattr(char *name, attrlist *items, pwu_repository_t *rep)
w->data.val_i = pw->pw_gid;
break;
case ATTR_LSTCHG:
- w->data.val_i = -1;
+ if (ldapbuf->shadow_update_enabled)
+ w->data.val_i = spw->sp_lstchg;
+ else
+ w->data.val_i = -1;
break;
case ATTR_MIN:
- w->data.val_i = -1;
+ if (ldapbuf->shadow_update_enabled)
+ w->data.val_i = spw->sp_min;
+ else
+ w->data.val_i = -1;
break;
case ATTR_MAX:
- w->data.val_i = -1;
+ if (ldapbuf->shadow_update_enabled)
+ w->data.val_i = spw->sp_max;
+ else
+ w->data.val_i = -1;
break;
case ATTR_WARN:
- w->data.val_i = -1;
+ if (ldapbuf->shadow_update_enabled)
+ w->data.val_i = spw->sp_warn;
+ else
+ w->data.val_i = -1;
break;
case ATTR_INACT:
- w->data.val_i = -1;
+ if (ldapbuf->shadow_update_enabled)
+ w->data.val_i = spw->sp_inact;
+ else
+ w->data.val_i = -1;
break;
case ATTR_EXPIRE:
- w->data.val_i = -1;
+ if (ldapbuf->shadow_update_enabled)
+ w->data.val_i = spw->sp_expire;
+ else
+ w->data.val_i = -1;
break;
case ATTR_FLAG:
+ if (ldapbuf->shadow_update_enabled)
+ w->data.val_i = spw->sp_flag;
+ break;
+ case ATTR_FAILED_LOGINS:
+ w->data.val_i = spw->sp_flag & FAILCOUNT_MASK;
break;
default:
break;
@@ -268,11 +385,8 @@ ldap_getattr(char *name, attrlist *items, pwu_repository_t *rep)
}
out:
- if (pw)
- free_pwd(pw);
- if (spw)
- free_spwd(spw);
-
+ free_ldapbuf(ldapbuf);
+ free(ldapbuf);
return (res);
}
@@ -292,45 +406,54 @@ int
ldap_getpwnam(char *name, attrlist *items, pwu_repository_t *rep,
void **buf)
{
- attrlist *p;
- int nr_items;
- int need_pwd = 0;
ldapbuf_t *ldapbuf;
- int res;
-
- for (nr_items = 0, p = items; p != NULL; p = p->next) {
- nr_items++;
- if (p->type == ATTR_PASSWD ||
- p->type == ATTR_PASSWD_SERVER_POLICY)
- need_pwd = 1;
- }
+ int res = PWU_NOMEM;
+ /*
+ * [sp]attrs is treated as NULL terminated
+ */
ldapbuf = calloc(1, sizeof (ldapbuf_t));
if (ldapbuf == NULL)
return (PWU_NOMEM);
- ldapbuf->attrs = calloc(nr_items, sizeof (ns_ldap_attr_t *));
- if (ldapbuf->attrs == NULL)
- return (PWU_NOMEM);
+ ldapbuf->pattrs = calloc(_PWD_MAX_ATTR, sizeof (ns_ldap_attr_t *));
+ if (ldapbuf->pattrs == NULL)
+ goto out;
+ ldapbuf->npattrs = _PWD_MAX_ATTR;
- if (need_pwd) {
- struct spwd *spw;
+ ldapbuf->sattrs = calloc(_S_MAX_ATTR, sizeof (ns_ldap_attr_t *));
+ if (ldapbuf->sattrs == NULL)
+ goto out;
+ ldapbuf->nsattrs = _S_MAX_ATTR;
- res = dup_pw(&ldapbuf->pwd, getpwnam_from(name, rep, REP_LDAP));
- if (res != PWU_SUCCESS)
- return (res);
+ res = dup_pw(&ldapbuf->pwd, getpwnam_from(name, rep, REP_LDAP));
+ if (res != PWU_SUCCESS)
+ goto out;
- spw = getspnam_from(name, rep, REP_LDAP);
- if (spw) {
- ldapbuf->passwd = strdup(spw->sp_pwdp);
+ res = dup_spw(&ldapbuf->spwd, getspnam_from(name, rep, REP_LDAP));
+ if (res != PWU_SUCCESS)
+ goto out;
+ else {
+ char *spw = ldapbuf->spwd->sp_pwdp;
+ if (spw != NULL && *spw != '\0') {
+ ldapbuf->passwd = strdup(spw);
if (ldapbuf->passwd == NULL)
- return (PWU_NOMEM);
- }
+ goto out;
+ } else
+ ldapbuf->passwd = NULL;
}
- *buf = ldapbuf;
- return (0);
+ /* remember if shadow update is enabled */
+ ldapbuf->shadow_update_enabled = __ns_ldap_is_shadow_update_enabled();
+
+ *buf = (void *)ldapbuf;
+ return (PWU_SUCCESS);
+
+out:
+ free_ldapbuf(ldapbuf);
+ free(ldapbuf);
+ return (res);
}
/*
@@ -359,6 +482,63 @@ new_attr(char *name, char *value)
}
/*
+ * max_present(list)
+ *
+ * returns '1' if a ATTR_MAX with value != -1 is present. (in other words:
+ * if password aging is to be turned on).
+ */
+static int
+max_present(attrlist *list)
+{
+ while (list != NULL)
+ if (list->type == ATTR_MAX && list->data.val_i != -1)
+ return (1);
+ else
+ list = list->next;
+ return (0);
+}
+
+/*
+ * attr_addmod(attrs, idx, item, val)
+ *
+ * Adds or updates attribute 'item' in ldap_attrs list to value
+ * update idx if item is added
+ * return: -1 - PWU_NOMEM/error, 0 - success
+ */
+static int
+attr_addmod(ns_ldap_attr_t **attrs, int *idx, char *item, int value)
+{
+ char numbuf[MAX_INT_LEN], *strp;
+ int i;
+
+ /* stringize the value or abort */
+ if (snprintf(numbuf, MAX_INT_LEN, "%d", value) >= MAX_INT_LEN)
+ return (-1);
+
+ /* check for existence and modify existing */
+ for (i = 0; i < *idx; i++) {
+ if (attrs[i] != NULL &&
+ strcmp(item, attrs[i]->attrname) == 0) {
+ strp = strdup(numbuf);
+ if (strp == NULL)
+ return (-1);
+ free(attrs[i]->attrvalue[0]);
+ attrs[i]->attrvalue[0] = strp;
+ return (0);
+ }
+ }
+ /* else add */
+ strp = strdup(numbuf);
+ if (strp == NULL)
+ return (-1);
+ attrs[*idx] = new_attr(item, strp);
+ if (attrs[*idx] == NULL)
+ return (-1);
+ (*idx)++;
+ return (0);
+}
+
+/*
* ldap_update(items, rep, buf)
*
* create LDAP attributes in 'buf' for each attribute in 'items'.
@@ -368,91 +548,399 @@ int
ldap_update(attrlist *items, pwu_repository_t *rep, void *buf)
{
attrlist *p;
- int idx = 0;
ldapbuf_t *ldapbuf = (ldapbuf_t *)buf;
- ns_ldap_attr_t **attrs = ldapbuf->attrs;
+ struct spwd *spw;
+ ns_ldap_attr_t **pattrs = ldapbuf->pattrs;
+ int pidx = 0;
+ ns_ldap_attr_t **sattrs = ldapbuf->sattrs;
+ int sidx = 0;
char *pwd, *val;
char *salt;
size_t cryptlen;
+ int len;
+ int count;
+ int rc = PWU_SUCCESS;
+ int aging_needed = 0;
+ int aging_set = 0;
+ int disable_aging;
+
+ spw = ldapbuf->spwd;
+
+ /*
+ * if sp_max==0 and shadow update is enabled:
+ * disable passwd aging after updating the password
+ */
+ disable_aging = (spw != NULL && spw->sp_max == 0 &&
+ ldapbuf->shadow_update_enabled);
for (p = items; p != NULL; p = p->next) {
switch (p->type) {
case ATTR_PASSWD:
- salt = crypt_gensalt(ldapbuf->passwd, ldapbuf->pwd);
-
- if (salt == NULL) {
- if (errno == ENOMEM)
+ /*
+ * There is a special case for ldap: if the
+ * password is to be deleted (-d to passwd),
+ * p->data.val_s will be NULL.
+ */
+ if (p->data.val_s == NULL) {
+ if (!ldapbuf->shadow_update_enabled)
+ return (PWU_CHANGE_NOT_ALLOWED);
+ cryptlen =
+ sizeof ("{crypt}" NS_LDAP_NO_UNIX_PASSWORD);
+ val = malloc(cryptlen);
+ if (val == NULL)
return (PWU_NOMEM);
- else {
+ (void) snprintf(val, cryptlen,
+ "{crypt}" NS_LDAP_NO_UNIX_PASSWORD);
+ } else { /* not deleting password */
+ salt = crypt_gensalt(ldapbuf->passwd,
+ ldapbuf->pwd);
+
+ if (salt == NULL) {
+ if (errno == ENOMEM)
+ return (PWU_NOMEM);
+
/* algorithm problem? */
syslog(LOG_AUTH | LOG_ALERT,
"passwdutil: crypt_gensalt "
"%m");
return (PWU_UPDATE_FAILED);
}
+
+ pwd = crypt(p->data.val_s, salt);
+ free(salt);
+ cryptlen = strlen(pwd) + sizeof ("{crypt}");
+ val = malloc(cryptlen);
+ if (val == NULL)
+ return (PWU_NOMEM);
+ (void) snprintf(val, cryptlen,
+ "{crypt}%s", pwd);
+ }
+
+ /*
+ * If not managing passwordAccount,
+ * insert the new password in the
+ * passwd attr array and break.
+ */
+ if (!ldapbuf->shadow_update_enabled) {
+ NEW_ATTR(pattrs, pidx,
+ _PWD_USERPASSWORD, val);
+ break;
}
- pwd = crypt(p->data.val_s, salt);
- free(salt);
- cryptlen = strlen(pwd) + sizeof ("{crypt}");
- val = malloc(cryptlen);
- if (val == NULL)
+ /*
+ * Managing passwordAccount, insert the
+ * new password, along with lastChange and
+ * shadowFlag, in the shadow attr array.
+ */
+ NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD, val);
+
+ if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE,
+ DAY_NOW_32) < 0)
return (PWU_NOMEM);
- (void) snprintf(val, cryptlen, "{crypt}%s", pwd);
+ spw->sp_lstchg = DAY_NOW_32;
- attrs[idx] = new_attr(_PWD_USERPASSWORD, val);
+ if (attr_addmod(sattrs, &sidx, _S_FLAG,
+ spw->sp_flag & ~FAILCOUNT_MASK) < 0)
+ return (PWU_NOMEM);
+ spw->sp_flag &= ~FAILCOUNT_MASK; /* reset count */
+ aging_needed = 1;
break;
- /*
- * For server policy, don't crypt the password,
- * send the password as is to the server and
- * let the LDAP server do its own password
- * encryption
- */
case ATTR_PASSWD_SERVER_POLICY:
- val = strdup(p->data.val_s);
- if (val == NULL)
- return (PWU_NOMEM);
-
- attrs[idx] = new_attr(_PWD_USERPASSWORD, val);
+ /*
+ * For server policy, don't crypt the password,
+ * send the password as is to the server and
+ * let the LDAP server do its own password
+ * encryption
+ */
+ STRDUP_OR_RET(val, p->data.val_s);
+
+ NEW_ATTR(pattrs, pidx, _PWD_USERPASSWORD, val);
break;
case ATTR_COMMENT:
/* XX correct? */
- attrs[idx] = new_attr(_PWD_DESCRIPTION, p->data.val_s);
+ NEW_ATTR(pattrs, pidx, _PWD_DESCRIPTION, p->data.val_s);
break;
case ATTR_GECOS:
- attrs[idx] = new_attr(_PWD_GECOS, p->data.val_s);
+ if (!ldapbuf->shadow_update_enabled) {
+ NEW_ATTR(pattrs, pidx, _PWD_GECOS,
+ p->data.val_s);
+ } else {
+ NEW_ATTR(sattrs, sidx, _PWD_GECOS,
+ p->data.val_s);
+ }
break;
case ATTR_HOMEDIR:
- attrs[idx] = new_attr(_PWD_HOMEDIRECTORY,
- p->data.val_s);
+ if (!ldapbuf->shadow_update_enabled) {
+ NEW_ATTR(pattrs, pidx, _PWD_HOMEDIRECTORY,
+ p->data.val_s);
+ } else {
+ NEW_ATTR(sattrs, sidx, _PWD_HOMEDIRECTORY,
+ p->data.val_s);
+ }
break;
case ATTR_SHELL:
- attrs[idx] = new_attr(_PWD_LOGINSHELL, p->data.val_s);
+ if (!ldapbuf->shadow_update_enabled) {
+ NEW_ATTR(pattrs, pidx, _PWD_LOGINSHELL,
+ p->data.val_s);
+ } else {
+ NEW_ATTR(sattrs, sidx, _PWD_LOGINSHELL,
+ p->data.val_s);
+ }
break;
- /* Unsupported items are below this line */
+ /* We don't update NAME, UID, GID */
case ATTR_NAME:
case ATTR_UID:
case ATTR_GID:
+ /* Unsupported item */
case ATTR_AGE:
+ break;
+ case ATTR_LOCK_ACCOUNT:
+ if (!ldapbuf->shadow_update_enabled)
+ break; /* not managing passwordAccount */
+ if (spw->sp_pwdp == NULL) {
+ spw->sp_pwdp = LOCKSTRING;
+ } else if (strncmp(spw->sp_pwdp, LOCKSTRING,
+ sizeof (LOCKSTRING)-1) != 0) {
+ len = sizeof (LOCKSTRING)-1 +
+ strlen(spw->sp_pwdp) + 1 +
+ sizeof ("{crypt}");
+ pwd = malloc(len);
+ if (pwd == NULL) {
+ return (PWU_NOMEM);
+ }
+ (void) strlcpy(pwd, "{crypt}", len);
+ (void) strlcat(pwd, LOCKSTRING, len);
+ (void) strlcat(pwd, spw->sp_pwdp, len);
+ free(spw->sp_pwdp);
+ spw->sp_pwdp = pwd;
+ NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD,
+ spw->sp_pwdp);
+ }
+ if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE,
+ DAY_NOW_32) < 0)
+ return (PWU_NOMEM);
+ spw->sp_lstchg = DAY_NOW_32;
+ break;
+
+ case ATTR_UNLOCK_ACCOUNT:
+ if (!ldapbuf->shadow_update_enabled)
+ break; /* not managing passwordAccount */
+ if (spw->sp_pwdp &&
+ strncmp(spw->sp_pwdp, LOCKSTRING,
+ sizeof (LOCKSTRING)-1) == 0) {
+ len = (sizeof ("{crypt}") -
+ sizeof (LOCKSTRING)) +
+ strlen(spw->sp_pwdp) + 1;
+ pwd = malloc(len);
+ if (pwd == NULL) {
+ return (PWU_NOMEM);
+ }
+ (void) strlcpy(pwd, "{crypt}", len);
+ (void) strlcat(pwd, spw->sp_pwdp +
+ sizeof (LOCKSTRING)-1, len);
+ free(spw->sp_pwdp);
+ spw->sp_pwdp = pwd;
+
+ NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD,
+ spw->sp_pwdp);
+ if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE,
+ DAY_NOW_32) < 0)
+ return (PWU_NOMEM);
+ spw->sp_lstchg = DAY_NOW_32;
+ }
+ break;
+
+ case ATTR_NOLOGIN_ACCOUNT:
+ if (!ldapbuf->shadow_update_enabled)
+ break; /* not managing passwordAccount */
+ free(spw->sp_pwdp);
+ STRDUP_OR_RET(spw->sp_pwdp, "{crypt}" NOLOGINSTRING);
+ NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD, spw->sp_pwdp);
+ if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE,
+ DAY_NOW_32) < 0)
+ return (PWU_NOMEM);
+ spw->sp_lstchg = DAY_NOW_32;
+ break;
+
+ case ATTR_EXPIRE_PASSWORD:
+ if (!ldapbuf->shadow_update_enabled)
+ break; /* not managing passwordAccount */
+ NUM_TO_STR(val, 0);
+ NEW_ATTR(sattrs, sidx, _S_LASTCHANGE, val);
+ break;
+
case ATTR_LSTCHG:
+ if (!ldapbuf->shadow_update_enabled)
+ break; /* not managing passwordAccount */
+ NUM_TO_STR(val, p->data.val_i);
+ NEW_ATTR(sattrs, sidx, _S_LASTCHANGE, val);
+ break;
+
case ATTR_MIN:
+ if (!ldapbuf->shadow_update_enabled)
+ break; /* not managing passwordAccount */
+ if (spw->sp_max == -1 && p->data.val_i != -1 &&
+ max_present(p->next) == 0)
+ return (PWU_AGING_DISABLED);
+ NUM_TO_STR(val, p->data.val_i);
+ NEW_ATTR(sattrs, sidx, _S_MIN, val);
+ aging_set = 1;
+ break;
+
case ATTR_MAX:
+ if (!ldapbuf->shadow_update_enabled)
+ break; /* not managing passwordAccount */
+ if (p->data.val_i == -1) {
+ /* Turn off aging. Reset min and warn too */
+ spw->sp_max = spw->sp_min = spw->sp_warn = -1;
+ NUM_TO_STR(val, -1);
+ NEW_ATTR(sattrs, sidx, _S_MIN, val);
+ NUM_TO_STR(val, -1);
+ NEW_ATTR(sattrs, sidx, _S_WARNING, val);
+ } else {
+ /* Turn account aging on */
+ if (spw->sp_min == -1) {
+ /*
+ * minage was not set with command-
+ * line option: set to zero
+ */
+ spw->sp_min = 0;
+ NUM_TO_STR(val, 0);
+ NEW_ATTR(sattrs, sidx, _S_MIN,
+ val);
+ }
+ /*
+ * If aging was turned off, we update lstchg.
+ * We take care not to update lstchg if the
+ * user has no password, otherwise the user
+ * might not be required to provide a password
+ * the next time [s]he logs in.
+ *
+ * Also, if lstchg != -1 (i.e., not set)
+ * we keep the old value.
+ */
+ if (spw->sp_max == -1 &&
+ spw->sp_pwdp != NULL && *spw->sp_pwdp &&
+ spw->sp_lstchg == -1) {
+ if (attr_addmod(sattrs, &sidx,
+ _S_LASTCHANGE,
+ DAY_NOW_32) < 0)
+ return (PWU_NOMEM);
+ spw->sp_lstchg = DAY_NOW_32;
+ }
+ }
+ NUM_TO_STR(val, p->data.val_i);
+ NEW_ATTR(sattrs, sidx, _S_MAX, val);
+ aging_set = 1;
+ break;
+
case ATTR_WARN:
+ if (!ldapbuf->shadow_update_enabled)
+ break; /* not managing passwordAccount */
+ if (spw->sp_max == -1 &&
+ p->data.val_i != -1 && max_present(p->next) == 0)
+ return (PWU_AGING_DISABLED);
+ NUM_TO_STR(val, p->data.val_i);
+ NEW_ATTR(sattrs, sidx, _S_WARNING, val);
+ break;
+
case ATTR_INACT:
+ if (!ldapbuf->shadow_update_enabled)
+ break; /* not managing passwordAccount */
+ NUM_TO_STR(val, p->data.val_i);
+ NEW_ATTR(sattrs, sidx, _S_INACTIVE, val);
+ break;
+
case ATTR_EXPIRE:
+ if (!ldapbuf->shadow_update_enabled)
+ break; /* not managing passwordAccount */
+ NUM_TO_STR(val, p->data.val_i);
+ NEW_ATTR(sattrs, sidx, _S_EXPIRE, val);
+ break;
+
case ATTR_FLAG:
+ if (!ldapbuf->shadow_update_enabled)
+ break; /* not managing passwordAccount */
+ NUM_TO_STR(val, p->data.val_i);
+ NEW_ATTR(sattrs, sidx, _S_FLAG, val);
+ break;
+ case ATTR_INCR_FAILED_LOGINS:
+ if (!ldapbuf->shadow_update_enabled) {
+ rc = PWU_CHANGE_NOT_ALLOWED;
+ break; /* not managing passwordAccount */
+ }
+ count = (spw->sp_flag & FAILCOUNT_MASK) + 1;
+ spw->sp_flag &= ~FAILCOUNT_MASK;
+ spw->sp_flag |= min(FAILCOUNT_MASK, count);
+ p->data.val_i = count;
+ NUM_TO_STR(val, spw->sp_flag);
+ NEW_ATTR(sattrs, sidx, _S_FLAG, val);
+ break;
+ case ATTR_RST_FAILED_LOGINS:
+ if (!ldapbuf->shadow_update_enabled) {
+ rc = PWU_CHANGE_NOT_ALLOWED;
+ break; /* not managing passwordAccount */
+ }
+ p->data.val_i = spw->sp_flag & FAILCOUNT_MASK;
+ spw->sp_flag &= ~FAILCOUNT_MASK;
+ NUM_TO_STR(val, spw->sp_flag);
+ NEW_ATTR(sattrs, sidx, _S_FLAG, val);
break;
default:
break;
}
- if (attrs[idx] == NULL)
- return (PWU_NOMEM);
- idx++;
}
- attrs[idx] = NULL;
+ /*
+ * If the ldap client is configured with shadow update enabled,
+ * then what should the new aging values look like?
+ *
+ * There are a number of different conditions
+ *
+ * a) aging is already configured: don't touch it
+ *
+ * b) disable_aging is set: disable aging
+ *
+ * c) aging is not configured: turn on default aging;
+ *
+ * b) and c) of course only if aging_needed and !aging_set.
+ * (i.e., password changed, and aging values not changed)
+ */
- return (PWU_SUCCESS);
+ if (ldapbuf->shadow_update_enabled && spw != NULL && spw->sp_max <= 0) {
+ /* a) aging not yet configured */
+ if (aging_needed && !aging_set) {
+ if (disable_aging) {
+ /* b) turn off aging */
+ spw->sp_min = spw->sp_max = spw->sp_warn = -1;
+ if (attr_addmod(sattrs, &sidx, _S_MIN, -1) < 0)
+ return (PWU_NOMEM);
+ if (attr_addmod(sattrs, &sidx, _S_MAX, -1) < 0)
+ return (PWU_NOMEM);
+ if (attr_addmod(sattrs, &sidx, _S_WARNING,
+ -1) < 0)
+ return (PWU_NOMEM);
+ } else {
+ /* c) */
+ turn_on_default_aging(spw);
+
+ if (attr_addmod(sattrs, &sidx, _S_MIN,
+ spw->sp_min) < 0)
+ return (PWU_NOMEM);
+ if (attr_addmod(sattrs, &sidx, _S_MAX,
+ spw->sp_max) < 0)
+ return (PWU_NOMEM);
+ if (attr_addmod(sattrs, &sidx,
+ _S_WARNING, spw->sp_warn) < 0)
+ return (PWU_NOMEM);
+ }
+ }
+ }
+
+ pattrs[pidx] = NULL;
+ sattrs[sidx] = NULL;
+
+ return (rc);
}
/*
@@ -492,7 +980,7 @@ ldap_to_pwu_code(int error, int pwd_status)
int
ldap_replaceattr(const char *dn, ns_ldap_attr_t **attrs, const char *binddn,
- const char *pwd, int *pwd_status)
+ const char *pwd, int *pwd_status, int flags)
{
int result = NS_LDAP_OP_FAILED;
int ldaprc;
@@ -507,18 +995,20 @@ ldap_replaceattr(const char *dn, ns_ldap_attr_t **attrs, const char *binddn,
debug("%s: replace_ldapattr()", __FILE__);
if ((credp = (ns_cred_t *)calloc(1, sizeof (ns_cred_t))) == NULL)
- return (PWU_NOMEM);
-
- /* Fill in the user name and password */
- if (dn == NULL || pwd == NULL)
- goto out;
+ return (NS_LDAP_MEMORY); /* map to PWU_NOMEM */
- credp->cred.unix_cred.userID = strdup(binddn);
- credp->cred.unix_cred.passwd = strdup(pwd);
+ /* for admin shadow update, dn and pwd will be set later in libsldap */
+ if ((flags & NS_LDAP_UPDATE_SHADOW) == 0) {
+ /* Fill in the user name and password */
+ if (dn == NULL || pwd == NULL)
+ goto out;
+ credp->cred.unix_cred.userID = strdup(binddn);
+ credp->cred.unix_cred.passwd = strdup(pwd);
+ }
/* get host certificate path, if one is configured */
ldaprc = __ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P,
- (void ***)&certpath, &errorp);
+ (void ***)&certpath, &errorp);
if (ldaprc != NS_LDAP_SUCCESS)
goto out;
@@ -527,7 +1017,7 @@ ldap_replaceattr(const char *dn, ns_ldap_attr_t **attrs, const char *binddn,
/* Load the service specific authentication method */
ldaprc = __ns_ldap_getServiceAuthMethods("passwd-cmd", &authpp,
- &errorp);
+ &errorp);
if (ldaprc != NS_LDAP_SUCCESS)
goto out;
@@ -538,7 +1028,7 @@ ldap_replaceattr(const char *dn, ns_ldap_attr_t **attrs, const char *binddn,
*/
if (authpp == NULL) {
ldaprc = __ns_ldap_getParam(NS_LDAP_AUTH_P, (void ***)&authpp,
- &errorp);
+ &errorp);
if (ldaprc != NS_LDAP_SUCCESS)
goto out;
}
@@ -570,21 +1060,32 @@ ldap_replaceattr(const char *dn, ns_ldap_attr_t **attrs, const char *binddn,
credp->auth.saslopt = authp->saslopt;
ldaprc = __ns_ldap_repAttr("shadow", dn,
- (const ns_ldap_attr_t * const *)attrs,
- credp, 0, &errorp);
+ (const ns_ldap_attr_t * const *)attrs,
+ credp, flags, &errorp);
if (ldaprc == NS_LDAP_SUCCESS) {
result = NS_LDAP_SUCCESS;
goto out;
}
/*
+ * if change not allowed due to configuration, indicate so
+ * to the caller
+ */
+ if (ldaprc == NS_LDAP_CONFIG &&
+ errorp->status == NS_CONFIG_NOTALLOW) {
+ result = NS_LDAP_CONFIG;
+ *pwd_status = NS_PASSWD_CHANGE_NOT_ALLOWED;
+ goto out;
+ }
+
+ /*
* other errors might need to be added to this list, for
* the current supported mechanisms this is sufficient
*/
if ((ldaprc == NS_LDAP_INTERNAL) &&
- (errorp->pwd_mgmt.status == NS_PASSWD_GOOD) &&
- ((errorp->status == LDAP_INAPPROPRIATE_AUTH) ||
- (errorp->status == LDAP_INVALID_CREDENTIALS))) {
+ (errorp->pwd_mgmt.status == NS_PASSWD_GOOD) &&
+ ((errorp->status == LDAP_INAPPROPRIATE_AUTH) ||
+ (errorp->status == LDAP_INVALID_CREDENTIALS))) {
result = ldaprc;
goto out;
}
@@ -594,7 +1095,7 @@ ldap_replaceattr(const char *dn, ns_ldap_attr_t **attrs, const char *binddn,
* return it to caller
*/
if ((ldaprc == NS_LDAP_INTERNAL) &&
- errorp->pwd_mgmt.status != NS_PASSWD_GOOD) {
+ errorp->pwd_mgmt.status != NS_PASSWD_GOOD) {
*pwd_status = errorp->pwd_mgmt.status;
result = ldaprc;
goto out;
@@ -611,7 +1112,7 @@ ldap_replaceattr(const char *dn, ns_ldap_attr_t **attrs, const char *binddn,
result = NS_LDAP_CONFIG;
goto out;
}
- result = PWU_DENIED;
+ result = NS_LDAP_OP_FAILED; /* map to PWU_DENIED */
out:
if (credp)
@@ -627,7 +1128,6 @@ out:
}
-
/*
* ldap_putpwnam(name, oldpw, dummy, rep, buf)
*
@@ -645,7 +1145,8 @@ ldap_putpwnam(char *name, char *oldpw, char *dummy,
char *binddn; /* dn of user who is performing the change */
ns_ldap_error_t *errorp;
ldapbuf_t *ldapbuf = (ldapbuf_t *)buf;
- ns_ldap_attr_t **attrs = ldapbuf->attrs;
+ ns_ldap_attr_t **pattrs = ldapbuf->pattrs;
+ ns_ldap_attr_t **sattrs = ldapbuf->sattrs;
struct passwd *pw;
int pwd_status;
uid_t uid;
@@ -654,6 +1155,26 @@ ldap_putpwnam(char *name, char *oldpw, char *dummy,
return (PWU_NOT_FOUND);
/*
+ * convert name of user whose attributes we are changing
+ * to a distinguished name
+ */
+ res = __ns_ldap_uid2dn(name, &dn, NULL, &errorp);
+ if (res != NS_LDAP_SUCCESS)
+ goto out;
+
+ /* update shadow via ldap_cachemgr if it is enabled */
+ if (ldapbuf->shadow_update_enabled &&
+ sattrs != NULL && sattrs[0] != NULL) {
+ /*
+ * flag NS_LDAP_UPDATE_SHADOW indicates the shadow update
+ * should be done via ldap_cachemgr
+ */
+ res = ldap_replaceattr(dn, sattrs, NULL, NULL, &pwd_status,
+ NS_LDAP_UPDATE_SHADOW);
+ goto out;
+ }
+
+ /*
* The LDAP server checks whether we are permitted to perform
* the requested change. We need to send the name of the user
* who is executing this piece of code, together with his
@@ -667,14 +1188,6 @@ ldap_putpwnam(char *name, char *oldpw, char *dummy,
*/
/*
- * convert name of user whose attributes we are changing
- * to a distinguished name
- */
- res = __ns_ldap_uid2dn(name, &dn, NULL, &errorp);
- if (res != NS_LDAP_SUCCESS)
- goto out;
-
- /*
* create a dn for the user who is executing this code
*/
uid = getuid();
@@ -696,21 +1209,14 @@ ldap_putpwnam(char *name, char *oldpw, char *dummy,
if (res != NS_LDAP_SUCCESS)
goto out;
- res = ldap_replaceattr(dn, attrs, binddn, oldpw,
- &pwd_status);
+ if (pattrs && pattrs[0] != NULL) {
+ res = ldap_replaceattr(dn, pattrs, binddn, oldpw,
+ &pwd_status, 0);
+ } else
+ res = NS_LDAP_OP_FAILED;
out:
- while (*attrs) {
- free((*attrs)->attrvalue[0]);
- free(*attrs);
- attrs++;
- }
- if (ldapbuf->passwd) {
- (void) memset(ldapbuf->passwd, 0, strlen(ldapbuf->passwd));
- free(ldapbuf->passwd);
- }
- if (ldapbuf->pwd)
- free_pwd(ldapbuf->pwd);
+ free_ldapbuf(ldapbuf);
free(dn);
return (ldap_to_pwu_code(res, pwd_status));
diff --git a/usr/src/lib/passwdutil/passwdutil.h b/usr/src/lib/passwdutil/passwdutil.h
index 65216e81e2..7634fce552 100644
--- a/usr/src/lib/passwdutil/passwdutil.h
+++ b/usr/src/lib/passwdutil/passwdutil.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -166,6 +166,7 @@ int get_ns(pwu_repository_t *, int);
struct passwd *getpwnam_from(const char *, pwu_repository_t *, int);
struct passwd *getpwuid_from(uid_t, pwu_repository_t *, int);
struct spwd *getspnam_from(const char *, pwu_repository_t *, int);
+int name_to_int(char *);
/*
* __set_authtok_attr.c