1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <shadow.h> 27 #include <stdlib.h> 28 #include "ldap_common.h" 29 30 /* shadow attributes filters */ 31 #define _S_UID "uid" 32 #define _S_USERPASSWORD "userpassword" 33 #define _S_LASTCHANGE "shadowlastchange" 34 #define _S_MIN "shadowmin" 35 #define _S_MAX "shadowmax" 36 #define _S_WARNING "shadowwarning" 37 #define _S_INACTIVE "shadowinactive" 38 #define _S_EXPIRE "shadowexpire" 39 #define _S_FLAG "shadowflag" 40 41 #define _F_GETSPNAM "(&(objectClass=shadowAccount)(uid=%s))" 42 #define _F_GETSPNAM_SSD "(&(%%s)(uid=%s))" 43 44 static const char *sp_attrs[] = { 45 _S_UID, 46 _S_USERPASSWORD, 47 _S_LASTCHANGE, 48 _S_MIN, 49 _S_MAX, 50 _S_WARNING, 51 _S_INACTIVE, 52 _S_EXPIRE, 53 _S_FLAG, 54 (char *)NULL 55 }; 56 57 /* 58 * _nss_ldap_shadow2str is the data marshaling method for the shadow getXbyY 59 * (e.g., getspnam(), getspent()) backend processes. This method is called after 60 * a successful ldap search has been performed. This method will parse the 61 * ldap search values into the file format. 62 * e.g. 63 * 64 * myname:gaBXNJuz4JDmA:6445:::::: 65 * 66 */ 67 68 static int 69 _nss_ldap_shadow2str(ldap_backend_ptr be, nss_XbyY_args_t *argp) 70 { 71 int nss_result; 72 int buflen = 0; 73 int shadow_update_enabled; 74 unsigned long len = 0L; 75 char *tmp, *buffer = NULL; 76 char *pw_passwd = NULL; 77 ns_ldap_result_t *result = be->result; 78 char **uid, **passwd, **last, **smin, **smax; 79 char **warning, **inactive, **expire, **flag; 80 char *last_str, *min_str, *max_str, *warning_str; 81 char *inactive_str, *expire_str, *flag_str; 82 83 if (result == NULL) 84 return (NSS_STR_PARSE_PARSE); 85 buflen = argp->buf.buflen; 86 87 nss_result = NSS_STR_PARSE_SUCCESS; 88 (void) memset(argp->buf.buffer, 0, buflen); 89 90 uid = __ns_ldap_getAttr(result->entry, _S_UID); 91 if (uid == NULL || uid[0] == NULL || (strlen(uid[0]) < 1)) { 92 nss_result = NSS_STR_PARSE_PARSE; 93 goto result_spd2str; 94 } 95 len += strlen(uid[0]); 96 97 passwd = __ns_ldap_getAttr(result->entry, _S_USERPASSWORD); 98 if (passwd == NULL || passwd[0] == NULL) { 99 /* 100 * ACL does not allow userpassword to return or 101 * userpassword is not defined 102 */ 103 pw_passwd = NOPWDRTR; 104 } else if (strcmp(passwd[0], "") == 0) { 105 /* 106 * An empty password is not supported 107 */ 108 nss_result = NSS_STR_PARSE_PARSE; 109 goto result_spd2str; 110 } else { 111 if ((tmp = strstr(passwd[0], "{crypt}")) != NULL || 112 (tmp = strstr(passwd[0], "{CRYPT}")) != NULL) { 113 if (tmp != passwd[0]) 114 pw_passwd = NOPWDRTR; 115 else { 116 pw_passwd = tmp + strlen("{crypt}"); 117 if (strcmp(pw_passwd, 118 NS_LDAP_NO_UNIX_PASSWORD) == 0) 119 *pw_passwd = '\0'; 120 } 121 } else { 122 /* mark password as not retrievable */ 123 pw_passwd = NOPWDRTR; 124 } 125 } 126 len += strlen(pw_passwd); 127 128 /* 129 * If shadow update is not enabled, ignore the following 130 * password aging related attributes: 131 * -- shadowlastchange 132 * -- shadowmin 133 * -- shadowmax 134 * -- shadowwarning 135 * -- shadowinactive 136 * -- shadowexpire 137 * When shadow update is not enabled, the LDAP naming 138 * service does not support the password aging fields 139 * defined in the shadow structure. These fields, sp_lstchg, 140 * sp_min, sp_max, sp_warn, sp_inact, and sp_expire, 141 * will be set to -1 by the front end marshaller. 142 */ 143 144 shadow_update_enabled = __ns_ldap_is_shadow_update_enabled(); 145 if (shadow_update_enabled) { 146 last = __ns_ldap_getAttr(result->entry, _S_LASTCHANGE); 147 if (last == NULL || last[0] == NULL) 148 last_str = _NO_VALUE; 149 else 150 last_str = last[0]; 151 len += strlen(last_str); 152 153 smin = __ns_ldap_getAttr(result->entry, _S_MIN); 154 if (smin == NULL || smin[0] == NULL) 155 min_str = _NO_VALUE; 156 else 157 min_str = smin[0]; 158 len += strlen(min_str); 159 160 smax = __ns_ldap_getAttr(result->entry, _S_MAX); 161 if (smax == NULL || smax[0] == NULL) 162 max_str = _NO_VALUE; 163 else 164 max_str = smax[0]; 165 len += strlen(max_str); 166 167 warning = __ns_ldap_getAttr(result->entry, _S_WARNING); 168 if (warning == NULL || warning[0] == NULL) 169 warning_str = _NO_VALUE; 170 else 171 warning_str = warning[0]; 172 len += strlen(warning_str); 173 174 inactive = __ns_ldap_getAttr(result->entry, _S_INACTIVE); 175 if (inactive == NULL || inactive[0] == NULL) 176 inactive_str = _NO_VALUE; 177 else 178 inactive_str = inactive[0]; 179 len += strlen(inactive_str); 180 181 expire = __ns_ldap_getAttr(result->entry, _S_EXPIRE); 182 if (expire == NULL || expire[0] == NULL) 183 expire_str = _NO_VALUE; 184 else 185 expire_str = expire[0]; 186 len += strlen(expire_str); 187 } 188 189 flag = __ns_ldap_getAttr(result->entry, _S_FLAG); 190 if (flag == NULL || flag[0] == NULL) 191 flag_str = _NO_VALUE; 192 else 193 flag_str = flag[0]; 194 195 /* 9 = 8 ':' + 1 '\0' */ 196 len += strlen(flag_str) + 9; 197 198 if (len > buflen) { 199 nss_result = NSS_STR_PARSE_ERANGE; 200 goto result_spd2str; 201 } 202 203 if (argp->buf.result != NULL) { 204 be->buffer = calloc(1, len); 205 if (be->buffer == NULL) { 206 nss_result = NSS_STR_PARSE_PARSE; 207 goto result_spd2str; 208 } 209 buffer = be->buffer; 210 } else 211 buffer = argp->buf.buffer; 212 213 if (shadow_update_enabled) { 214 (void) snprintf(buffer, len, "%s:%s:%s:%s:%s:%s:%s:%s:%s", 215 uid[0], pw_passwd, last_str, min_str, max_str, warning_str, 216 inactive_str, expire_str, flag_str); 217 } else { 218 (void) snprintf(buffer, len, "%s:%s:::::::%s", 219 uid[0], pw_passwd, flag_str); 220 } 221 222 /* The front end marhsaller doesn't need the trailing null */ 223 if (argp->buf.result != NULL) 224 be->buflen = strlen(be->buffer); 225 result_spd2str: 226 227 (void) __ns_ldap_freeResult(&be->result); 228 return ((int)nss_result); 229 } 230 231 /* 232 * getbynam gets a passwd entry by uid name. This function constructs an ldap 233 * search filter using the name invocation parameter and the getspnam search 234 * filter defined. Once the filter is constructed we search for a matching 235 * entry and marshal the data results into struct shadow for the frontend 236 * process. The function _nss_ldap_shadow2ent performs the data marshaling. 237 */ 238 239 static nss_status_t 240 getbynam(ldap_backend_ptr be, void *a) 241 { 242 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 243 char searchfilter[SEARCHFILTERLEN]; 244 char userdata[SEARCHFILTERLEN]; 245 char name[SEARCHFILTERLEN + 1]; 246 int ret; 247 248 if (_ldap_filter_name(name, argp->key.name, sizeof (name)) != 0) 249 return ((nss_status_t)NSS_NOTFOUND); 250 251 ret = snprintf(searchfilter, sizeof (searchfilter), _F_GETSPNAM, name); 252 if (ret >= sizeof (searchfilter) || ret < 0) 253 return ((nss_status_t)NSS_NOTFOUND); 254 255 ret = snprintf(userdata, sizeof (userdata), _F_GETSPNAM_SSD, name); 256 if (ret >= sizeof (userdata) || ret < 0) 257 return ((nss_status_t)NSS_NOTFOUND); 258 259 return (_nss_ldap_lookup(be, argp, _SHADOW, searchfilter, NULL, 260 _merge_SSD_filter, userdata)); 261 } 262 263 static ldap_backend_op_t sp_ops[] = { 264 _nss_ldap_destr, 265 _nss_ldap_endent, 266 _nss_ldap_setent, 267 _nss_ldap_getent, 268 getbynam 269 }; 270 271 272 /* 273 * _nss_ldap_passwd_constr is where life begins. This function calls the 274 * generic ldap constructor function to define and build the abstract 275 * data types required to support ldap operations. 276 */ 277 278 /*ARGSUSED0*/ 279 nss_backend_t * 280 _nss_ldap_shadow_constr(const char *dummy1, const char *dummy2, 281 const char *dummy3) 282 { 283 284 return ((nss_backend_t *)_nss_ldap_constr(sp_ops, 285 sizeof (sp_ops)/sizeof (sp_ops[0]), 286 _SHADOW, sp_attrs, _nss_ldap_shadow2str)); 287 } 288