17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5cb5caa98Sdjl * Common Development and Distribution License (the "License"). 6cb5caa98Sdjl * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*dd1104fbSMichen Chang * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #include <shadow.h> 277c478bd9Sstevel@tonic-gate #include <stdlib.h> 287c478bd9Sstevel@tonic-gate #include "ldap_common.h" 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate /* shadow attributes filters */ 317c478bd9Sstevel@tonic-gate #define _S_UID "uid" 327c478bd9Sstevel@tonic-gate #define _S_USERPASSWORD "userpassword" 33*dd1104fbSMichen Chang #define _S_LASTCHANGE "shadowlastchange" 34*dd1104fbSMichen Chang #define _S_MIN "shadowmin" 35*dd1104fbSMichen Chang #define _S_MAX "shadowmax" 36*dd1104fbSMichen Chang #define _S_WARNING "shadowwarning" 37*dd1104fbSMichen Chang #define _S_INACTIVE "shadowinactive" 38*dd1104fbSMichen Chang #define _S_EXPIRE "shadowexpire" 397c478bd9Sstevel@tonic-gate #define _S_FLAG "shadowflag" 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate #define _F_GETSPNAM "(&(objectClass=shadowAccount)(uid=%s))" 427c478bd9Sstevel@tonic-gate #define _F_GETSPNAM_SSD "(&(%%s)(uid=%s))" 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate static const char *sp_attrs[] = { 457c478bd9Sstevel@tonic-gate _S_UID, 467c478bd9Sstevel@tonic-gate _S_USERPASSWORD, 47*dd1104fbSMichen Chang _S_LASTCHANGE, 48*dd1104fbSMichen Chang _S_MIN, 49*dd1104fbSMichen Chang _S_MAX, 50*dd1104fbSMichen Chang _S_WARNING, 51*dd1104fbSMichen Chang _S_INACTIVE, 52*dd1104fbSMichen Chang _S_EXPIRE, 537c478bd9Sstevel@tonic-gate _S_FLAG, 547c478bd9Sstevel@tonic-gate (char *)NULL 557c478bd9Sstevel@tonic-gate }; 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate /* 58cb5caa98Sdjl * _nss_ldap_shadow2str is the data marshaling method for the shadow getXbyY 597c478bd9Sstevel@tonic-gate * (e.g., getspnam(), getspent()) backend processes. This method is called after 607c478bd9Sstevel@tonic-gate * a successful ldap search has been performed. This method will parse the 61cb5caa98Sdjl * ldap search values into the file format. 62cb5caa98Sdjl * e.g. 63cb5caa98Sdjl * 64cb5caa98Sdjl * myname:gaBXNJuz4JDmA:6445:::::: 65cb5caa98Sdjl * 667c478bd9Sstevel@tonic-gate */ 677c478bd9Sstevel@tonic-gate 687c478bd9Sstevel@tonic-gate static int 69cb5caa98Sdjl _nss_ldap_shadow2str(ldap_backend_ptr be, nss_XbyY_args_t *argp) 707c478bd9Sstevel@tonic-gate { 717c478bd9Sstevel@tonic-gate int nss_result; 72cb5caa98Sdjl int buflen = 0; 73*dd1104fbSMichen Chang int shadow_update_enabled; 747c478bd9Sstevel@tonic-gate unsigned long len = 0L; 75cb5caa98Sdjl char *tmp, *buffer = NULL; 76cb5caa98Sdjl char *pw_passwd = NULL; 777c478bd9Sstevel@tonic-gate ns_ldap_result_t *result = be->result; 78*dd1104fbSMichen Chang char **uid, **passwd, **last, **smin, **smax; 79*dd1104fbSMichen Chang char **warning, **inactive, **expire, **flag; 80*dd1104fbSMichen Chang char *last_str, *min_str, *max_str, *warning_str; 81*dd1104fbSMichen Chang char *inactive_str, *expire_str, *flag_str; 827c478bd9Sstevel@tonic-gate 83cb5caa98Sdjl if (result == NULL) 84cb5caa98Sdjl return (NSS_STR_PARSE_PARSE); 85cb5caa98Sdjl buflen = argp->buf.buflen; 867c478bd9Sstevel@tonic-gate 87cb5caa98Sdjl nss_result = NSS_STR_PARSE_SUCCESS; 88cb5caa98Sdjl (void) memset(argp->buf.buffer, 0, buflen); 89cb5caa98Sdjl 90cb5caa98Sdjl uid = __ns_ldap_getAttr(result->entry, _S_UID); 91cb5caa98Sdjl if (uid == NULL || uid[0] == NULL || (strlen(uid[0]) < 1)) { 92cb5caa98Sdjl nss_result = NSS_STR_PARSE_PARSE; 93cb5caa98Sdjl goto result_spd2str; 947c478bd9Sstevel@tonic-gate } 95cb5caa98Sdjl len += strlen(uid[0]); 967c478bd9Sstevel@tonic-gate 97cb5caa98Sdjl passwd = __ns_ldap_getAttr(result->entry, _S_USERPASSWORD); 98a1e48794Schinlong if (passwd == NULL || passwd[0] == NULL) { 99a1e48794Schinlong /* 100a1e48794Schinlong * ACL does not allow userpassword to return or 101a1e48794Schinlong * userpassword is not defined 102a1e48794Schinlong */ 10366e150d7SJohn Sonnenschein pw_passwd = NOPWDRTR; 104a1e48794Schinlong } else if (strcmp(passwd[0], "") == 0) { 105a1e48794Schinlong /* 106a1e48794Schinlong * An empty password is not supported 107a1e48794Schinlong */ 108a1e48794Schinlong nss_result = NSS_STR_PARSE_PARSE; 109a1e48794Schinlong goto result_spd2str; 110cb5caa98Sdjl } else { 111cb5caa98Sdjl if ((tmp = strstr(passwd[0], "{crypt}")) != NULL || 112cb5caa98Sdjl (tmp = strstr(passwd[0], "{CRYPT}")) != NULL) { 113cb5caa98Sdjl if (tmp != passwd[0]) 11466e150d7SJohn Sonnenschein pw_passwd = NOPWDRTR; 115*dd1104fbSMichen Chang else { 116cb5caa98Sdjl pw_passwd = tmp + strlen("{crypt}"); 117*dd1104fbSMichen Chang if (strcmp(pw_passwd, 118*dd1104fbSMichen Chang NS_LDAP_NO_UNIX_PASSWORD) == 0) 119*dd1104fbSMichen Chang *pw_passwd = '\0'; 120*dd1104fbSMichen Chang } 1217c478bd9Sstevel@tonic-gate } else { 12266e150d7SJohn Sonnenschein /* mark password as not retrievable */ 12366e150d7SJohn Sonnenschein pw_passwd = NOPWDRTR; 1247c478bd9Sstevel@tonic-gate } 1257c478bd9Sstevel@tonic-gate } 126cb5caa98Sdjl len += strlen(pw_passwd); 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate /* 129*dd1104fbSMichen Chang * If shadow update is not enabled, ignore the following 130*dd1104fbSMichen Chang * password aging related attributes: 1317c478bd9Sstevel@tonic-gate * -- shadowlastchange 1327c478bd9Sstevel@tonic-gate * -- shadowmin 1337c478bd9Sstevel@tonic-gate * -- shadowmax 1347c478bd9Sstevel@tonic-gate * -- shadowwarning 1357c478bd9Sstevel@tonic-gate * -- shadowinactive 1367c478bd9Sstevel@tonic-gate * -- shadowexpire 137*dd1104fbSMichen Chang * When shadow update is not enabled, the LDAP naming 138*dd1104fbSMichen Chang * service does not support the password aging fields 139*dd1104fbSMichen Chang * defined in the shadow structure. These fields, sp_lstchg, 1407c478bd9Sstevel@tonic-gate * sp_min, sp_max, sp_warn, sp_inact, and sp_expire, 141cb5caa98Sdjl * will be set to -1 by the front end marshaller. 1427c478bd9Sstevel@tonic-gate */ 143*dd1104fbSMichen Chang 144*dd1104fbSMichen Chang shadow_update_enabled = __ns_ldap_is_shadow_update_enabled(); 145*dd1104fbSMichen Chang if (shadow_update_enabled) { 146*dd1104fbSMichen Chang last = __ns_ldap_getAttr(result->entry, _S_LASTCHANGE); 147*dd1104fbSMichen Chang if (last == NULL || last[0] == NULL) 148*dd1104fbSMichen Chang last_str = _NO_VALUE; 149*dd1104fbSMichen Chang else 150*dd1104fbSMichen Chang last_str = last[0]; 151*dd1104fbSMichen Chang len += strlen(last_str); 152*dd1104fbSMichen Chang 153*dd1104fbSMichen Chang smin = __ns_ldap_getAttr(result->entry, _S_MIN); 154*dd1104fbSMichen Chang if (smin == NULL || smin[0] == NULL) 155*dd1104fbSMichen Chang min_str = _NO_VALUE; 156*dd1104fbSMichen Chang else 157*dd1104fbSMichen Chang min_str = smin[0]; 158*dd1104fbSMichen Chang len += strlen(min_str); 159*dd1104fbSMichen Chang 160*dd1104fbSMichen Chang smax = __ns_ldap_getAttr(result->entry, _S_MAX); 161*dd1104fbSMichen Chang if (smax == NULL || smax[0] == NULL) 162*dd1104fbSMichen Chang max_str = _NO_VALUE; 163*dd1104fbSMichen Chang else 164*dd1104fbSMichen Chang max_str = smax[0]; 165*dd1104fbSMichen Chang len += strlen(max_str); 166*dd1104fbSMichen Chang 167*dd1104fbSMichen Chang warning = __ns_ldap_getAttr(result->entry, _S_WARNING); 168*dd1104fbSMichen Chang if (warning == NULL || warning[0] == NULL) 169*dd1104fbSMichen Chang warning_str = _NO_VALUE; 170*dd1104fbSMichen Chang else 171*dd1104fbSMichen Chang warning_str = warning[0]; 172*dd1104fbSMichen Chang len += strlen(warning_str); 173*dd1104fbSMichen Chang 174*dd1104fbSMichen Chang inactive = __ns_ldap_getAttr(result->entry, _S_INACTIVE); 175*dd1104fbSMichen Chang if (inactive == NULL || inactive[0] == NULL) 176*dd1104fbSMichen Chang inactive_str = _NO_VALUE; 177*dd1104fbSMichen Chang else 178*dd1104fbSMichen Chang inactive_str = inactive[0]; 179*dd1104fbSMichen Chang len += strlen(inactive_str); 180*dd1104fbSMichen Chang 181*dd1104fbSMichen Chang expire = __ns_ldap_getAttr(result->entry, _S_EXPIRE); 182*dd1104fbSMichen Chang if (expire == NULL || expire[0] == NULL) 183*dd1104fbSMichen Chang expire_str = _NO_VALUE; 184*dd1104fbSMichen Chang else 185*dd1104fbSMichen Chang expire_str = expire[0]; 186*dd1104fbSMichen Chang len += strlen(expire_str); 187*dd1104fbSMichen Chang } 188*dd1104fbSMichen Chang 189cb5caa98Sdjl flag = __ns_ldap_getAttr(result->entry, _S_FLAG); 190cb5caa98Sdjl if (flag == NULL || flag[0] == NULL) 191cb5caa98Sdjl flag_str = _NO_VALUE; 192cb5caa98Sdjl else 193cb5caa98Sdjl flag_str = flag[0]; 1947c478bd9Sstevel@tonic-gate 195cb5caa98Sdjl /* 9 = 8 ':' + 1 '\0' */ 196cb5caa98Sdjl len += strlen(flag_str) + 9; 197cb5caa98Sdjl 198cb5caa98Sdjl if (len > buflen) { 199cb5caa98Sdjl nss_result = NSS_STR_PARSE_ERANGE; 200cb5caa98Sdjl goto result_spd2str; 2017c478bd9Sstevel@tonic-gate } 2027c478bd9Sstevel@tonic-gate 203cb5caa98Sdjl if (argp->buf.result != NULL) { 204cb5caa98Sdjl be->buffer = calloc(1, len); 205cb5caa98Sdjl if (be->buffer == NULL) { 206cb5caa98Sdjl nss_result = NSS_STR_PARSE_PARSE; 207cb5caa98Sdjl goto result_spd2str; 2087c478bd9Sstevel@tonic-gate } 209cb5caa98Sdjl buffer = be->buffer; 210cb5caa98Sdjl } else 211cb5caa98Sdjl buffer = argp->buf.buffer; 2127c478bd9Sstevel@tonic-gate 213*dd1104fbSMichen Chang if (shadow_update_enabled) { 214*dd1104fbSMichen Chang (void) snprintf(buffer, len, "%s:%s:%s:%s:%s:%s:%s:%s:%s", 215*dd1104fbSMichen Chang uid[0], pw_passwd, last_str, min_str, max_str, warning_str, 216*dd1104fbSMichen Chang inactive_str, expire_str, flag_str); 217*dd1104fbSMichen Chang } else { 218cb5caa98Sdjl (void) snprintf(buffer, len, "%s:%s:::::::%s", 219cb5caa98Sdjl uid[0], pw_passwd, flag_str); 220*dd1104fbSMichen Chang } 2217c478bd9Sstevel@tonic-gate 222cb5caa98Sdjl /* The front end marhsaller doesn't need the trailing null */ 223cb5caa98Sdjl if (argp->buf.result != NULL) 224cb5caa98Sdjl be->buflen = strlen(be->buffer); 225cb5caa98Sdjl result_spd2str: 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate (void) __ns_ldap_freeResult(&be->result); 2287c478bd9Sstevel@tonic-gate return ((int)nss_result); 2297c478bd9Sstevel@tonic-gate } 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate /* 2327c478bd9Sstevel@tonic-gate * getbynam gets a passwd entry by uid name. This function constructs an ldap 2337c478bd9Sstevel@tonic-gate * search filter using the name invocation parameter and the getspnam search 2347c478bd9Sstevel@tonic-gate * filter defined. Once the filter is constructed we search for a matching 2357c478bd9Sstevel@tonic-gate * entry and marshal the data results into struct shadow for the frontend 2367c478bd9Sstevel@tonic-gate * process. The function _nss_ldap_shadow2ent performs the data marshaling. 2377c478bd9Sstevel@tonic-gate */ 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate static nss_status_t 2407c478bd9Sstevel@tonic-gate getbynam(ldap_backend_ptr be, void *a) 2417c478bd9Sstevel@tonic-gate { 2427c478bd9Sstevel@tonic-gate nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 2437c478bd9Sstevel@tonic-gate char searchfilter[SEARCHFILTERLEN]; 2447c478bd9Sstevel@tonic-gate char userdata[SEARCHFILTERLEN]; 2457c478bd9Sstevel@tonic-gate char name[SEARCHFILTERLEN + 1]; 2467c478bd9Sstevel@tonic-gate int ret; 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate if (_ldap_filter_name(name, argp->key.name, sizeof (name)) != 0) 2497c478bd9Sstevel@tonic-gate return ((nss_status_t)NSS_NOTFOUND); 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate ret = snprintf(searchfilter, sizeof (searchfilter), _F_GETSPNAM, name); 2527c478bd9Sstevel@tonic-gate if (ret >= sizeof (searchfilter) || ret < 0) 2537c478bd9Sstevel@tonic-gate return ((nss_status_t)NSS_NOTFOUND); 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate ret = snprintf(userdata, sizeof (userdata), _F_GETSPNAM_SSD, name); 2567c478bd9Sstevel@tonic-gate if (ret >= sizeof (userdata) || ret < 0) 2577c478bd9Sstevel@tonic-gate return ((nss_status_t)NSS_NOTFOUND); 2587c478bd9Sstevel@tonic-gate 2597c478bd9Sstevel@tonic-gate return (_nss_ldap_lookup(be, argp, _SHADOW, searchfilter, NULL, 2607c478bd9Sstevel@tonic-gate _merge_SSD_filter, userdata)); 2617c478bd9Sstevel@tonic-gate } 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate static ldap_backend_op_t sp_ops[] = { 2647c478bd9Sstevel@tonic-gate _nss_ldap_destr, 2657c478bd9Sstevel@tonic-gate _nss_ldap_endent, 2667c478bd9Sstevel@tonic-gate _nss_ldap_setent, 2677c478bd9Sstevel@tonic-gate _nss_ldap_getent, 2687c478bd9Sstevel@tonic-gate getbynam 2697c478bd9Sstevel@tonic-gate }; 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate /* 2737c478bd9Sstevel@tonic-gate * _nss_ldap_passwd_constr is where life begins. This function calls the 2747c478bd9Sstevel@tonic-gate * generic ldap constructor function to define and build the abstract 2757c478bd9Sstevel@tonic-gate * data types required to support ldap operations. 2767c478bd9Sstevel@tonic-gate */ 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate /*ARGSUSED0*/ 2797c478bd9Sstevel@tonic-gate nss_backend_t * 2807c478bd9Sstevel@tonic-gate _nss_ldap_shadow_constr(const char *dummy1, const char *dummy2, 2817c478bd9Sstevel@tonic-gate const char *dummy3) 2827c478bd9Sstevel@tonic-gate { 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate return ((nss_backend_t *)_nss_ldap_constr(sp_ops, 2857c478bd9Sstevel@tonic-gate sizeof (sp_ops)/sizeof (sp_ops[0]), 286cb5caa98Sdjl _SHADOW, sp_attrs, _nss_ldap_shadow2str)); 2877c478bd9Sstevel@tonic-gate } 288