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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <shadow.h> 30 #include <stdlib.h> 31 #include "ldap_common.h" 32 33 /* shadow attributes filters */ 34 #define _S_CN "cn" 35 #define _S_UID "uid" 36 #define _S_USERPASSWORD "userpassword" 37 #define _S_FLAG "shadowflag" 38 39 #define _F_GETSPNAM "(&(objectClass=shadowAccount)(uid=%s))" 40 #define _F_GETSPNAM_SSD "(&(%%s)(uid=%s))" 41 42 static const char *sp_attrs[] = { 43 _S_UID, 44 _S_USERPASSWORD, 45 _S_FLAG, 46 (char *)NULL 47 }; 48 49 50 extern ns_ldap_attr_t *getattr(ns_ldap_result_t *result, int i); 51 52 /* 53 * _nss_ldap_shadow2ent is the data marshaling method for the passwd getXbyY 54 * (e.g., getspnam(), getspent()) backend processes. This method is called after 55 * a successful ldap search has been performed. This method will parse the 56 * ldap search values into struct spwd = argp->buf.buffer which the frontend 57 * process expects. Three error conditions are expected and returned to 58 * nsswitch. 59 */ 60 61 static int 62 _nss_ldap_shadow2ent(ldap_backend_ptr be, nss_XbyY_args_t *argp) 63 { 64 int i = 0; 65 int nss_result; 66 int buflen = (int)0; 67 unsigned long len = 0L; 68 char *buffer = (char *)NULL; 69 char *ceiling = (char *)NULL; 70 char *pw_passwd = (char *)NULL; 71 char *nullstring = (char *)NULL; 72 char np[] = "*NP*"; 73 ns_ldap_result_t *result = be->result; 74 ns_ldap_attr_t *attrptr; 75 long ltmp = (long)0L; 76 struct spwd *spd = (struct spwd *)NULL; 77 78 #ifdef DEBUG 79 (void) fprintf(stdout, "\n[getspent.c: _nss_ldap_shadow2ent]\n"); 80 #endif /* DEBUG */ 81 82 buffer = argp->buf.buffer; 83 buflen = (size_t)argp->buf.buflen; 84 if (!argp->buf.result) { 85 nss_result = (int)NSS_STR_PARSE_ERANGE; 86 goto result_spd2ent; 87 } 88 spd = (struct spwd *)argp->buf.result; 89 ceiling = buffer + buflen; 90 nullstring = (buffer + (buflen - 1)); 91 92 /* Default values */ 93 spd->sp_lstchg = -1; spd->sp_min = -1; 94 spd->sp_max = -1; spd->sp_warn = -1; 95 spd->sp_inact = -1; spd->sp_expire = -1; 96 spd->sp_flag = 0; spd->sp_pwdp = NULL; 97 98 nss_result = (int)NSS_STR_PARSE_SUCCESS; 99 (void) memset(buffer, 0, buflen); 100 101 attrptr = getattr(result, 0); 102 if (attrptr == NULL) { 103 nss_result = (int)NSS_STR_PARSE_PARSE; 104 goto result_spd2ent; 105 } 106 107 for (i = 0; i < result->entry->attr_count; i++) { 108 attrptr = getattr(result, i); 109 if (strcasecmp(attrptr->attrname, _S_UID) == 0) { 110 if ((attrptr->attrvalue[0] == NULL) || 111 (len = strlen(attrptr->attrvalue[0])) < 1) { 112 nss_result = (int)NSS_STR_PARSE_PARSE; 113 goto result_spd2ent; 114 } 115 spd->sp_namp = buffer; 116 buffer += len + 1; 117 if (buffer >= ceiling) { 118 nss_result = (int)NSS_STR_PARSE_ERANGE; 119 goto result_spd2ent; 120 } 121 (void) strcpy(spd->sp_namp, attrptr->attrvalue[0]); 122 continue; 123 } 124 if (strcasecmp(attrptr->attrname, _S_USERPASSWORD) == 0) { 125 if (attrptr->attrvalue[0] == '\0') { 126 spd->sp_pwdp = nullstring; 127 nss_result = (int)NSS_STR_PARSE_PARSE; 128 goto result_spd2ent; 129 } 130 pw_passwd = attrptr->attrvalue[0]; 131 if (pw_passwd) { 132 char *tmp; 133 134 if ((tmp = strstr(pw_passwd, "{crypt}")) 135 != NULL) { 136 if (tmp != pw_passwd) 137 pw_passwd = np; 138 else 139 pw_passwd += 7; 140 } else if ((tmp = strstr(pw_passwd, "{CRYPT}")) 141 != NULL) { 142 if (tmp != pw_passwd) 143 pw_passwd = np; 144 else 145 pw_passwd += 7; 146 } else { 147 pw_passwd = np; 148 } 149 } 150 len = (unsigned long)strlen(pw_passwd); 151 if (len < 1) { 152 spd->sp_pwdp = nullstring; 153 } else { 154 spd->sp_pwdp = buffer; 155 buffer += len + 1; 156 if (buffer >= ceiling) { 157 nss_result = (int)NSS_STR_PARSE_ERANGE; 158 goto result_spd2ent; 159 } 160 } 161 (void) strcpy(spd->sp_pwdp, pw_passwd); 162 } 163 164 /* 165 * Ignore the following password aging related attributes: 166 * -- shadowlastchange 167 * -- shadowmin 168 * -- shadowmax 169 * -- shadowwarning 170 * -- shadowinactive 171 * -- shadowexpire 172 * This is because the LDAP naming service does not 173 * really support the password aging fields defined 174 * in the shadow structure. These fields, sp_lstchg, 175 * sp_min, sp_max, sp_warn, sp_inact, and sp_expire, 176 * have been set to -1. 177 */ 178 179 if (strcasecmp(attrptr->attrname, _S_FLAG) == 0) { 180 if (attrptr->attrvalue[0] == '\0') { 181 nss_result = (int)NSS_STR_PARSE_PARSE; 182 goto result_spd2ent; 183 } 184 errno = 0; 185 ltmp = strtol(attrptr->attrvalue[0], (char **)NULL, 10); 186 if (errno != 0) { 187 nss_result = (int)NSS_STR_PARSE_PARSE; 188 goto result_spd2ent; 189 } 190 spd->sp_flag = (int)ltmp; 191 continue; 192 } 193 } 194 195 /* we will not allow for an empty password to be */ 196 /* returned to the front end as this is not a supported */ 197 /* configuration. Since we got to this point without */ 198 /* the password being set, we assume that no password was */ 199 /* set on the server which is consider a misconfiguration. */ 200 /* We will proceed and set the password to *NP* as no password */ 201 /* is not supported */ 202 203 if (spd->sp_pwdp == NULL) { 204 spd->sp_pwdp = buffer; 205 buffer += strlen(np) + 1; 206 if (buffer >= ceiling) { 207 nss_result = (int)NSS_STR_PARSE_ERANGE; 208 goto result_spd2ent; 209 } 210 strcpy(spd->sp_pwdp, np); 211 } 212 213 214 #ifdef DEBUG 215 (void) fprintf(stdout, "\n[getspent.c: _nss_ldap_shadow2ent]\n"); 216 (void) fprintf(stdout, " sp_namp: [%s]\n", spd->sp_namp); 217 (void) fprintf(stdout, " sp_pwdp: [%s]\n", spd->sp_pwdp); 218 (void) fprintf(stdout, " sp_latchg: [%d]\n", spd->sp_lstchg); 219 (void) fprintf(stdout, " sp_min: [%d]\n", spd->sp_min); 220 (void) fprintf(stdout, " sp_max: [%d]\n", spd->sp_max); 221 (void) fprintf(stdout, " sp_warn: [%d]\n", spd->sp_warn); 222 (void) fprintf(stdout, " sp_inact: [%d]\n", spd->sp_inact); 223 (void) fprintf(stdout, " sp_expire: [%d]\n", spd->sp_expire); 224 (void) fprintf(stdout, " sp_flag: [%d]\n", spd->sp_flag); 225 #endif /* DEBUG */ 226 227 result_spd2ent: 228 229 (void) __ns_ldap_freeResult(&be->result); 230 return ((int)nss_result); 231 } 232 233 /* 234 * getbynam gets a passwd entry by uid name. This function constructs an ldap 235 * search filter using the name invocation parameter and the getspnam search 236 * filter defined. Once the filter is constructed we search for a matching 237 * entry and marshal the data results into struct shadow for the frontend 238 * process. The function _nss_ldap_shadow2ent performs the data marshaling. 239 */ 240 241 static nss_status_t 242 getbynam(ldap_backend_ptr be, void *a) 243 { 244 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 245 char searchfilter[SEARCHFILTERLEN]; 246 char userdata[SEARCHFILTERLEN]; 247 char name[SEARCHFILTERLEN + 1]; 248 int len; 249 int ret; 250 251 #ifdef DEBUG 252 (void) fprintf(stdout, "\n[getspent.c: getbynam]\n"); 253 #endif /* DEBUG */ 254 255 if (_ldap_filter_name(name, argp->key.name, sizeof (name)) != 0) 256 return ((nss_status_t)NSS_NOTFOUND); 257 258 ret = snprintf(searchfilter, sizeof (searchfilter), _F_GETSPNAM, name); 259 if (ret >= sizeof (searchfilter) || ret < 0) 260 return ((nss_status_t)NSS_NOTFOUND); 261 262 ret = snprintf(userdata, sizeof (userdata), _F_GETSPNAM_SSD, name); 263 if (ret >= sizeof (userdata) || ret < 0) 264 return ((nss_status_t)NSS_NOTFOUND); 265 266 return (_nss_ldap_lookup(be, argp, _SHADOW, searchfilter, NULL, 267 _merge_SSD_filter, userdata)); 268 } 269 270 static ldap_backend_op_t sp_ops[] = { 271 _nss_ldap_destr, 272 _nss_ldap_endent, 273 _nss_ldap_setent, 274 _nss_ldap_getent, 275 getbynam 276 }; 277 278 279 /* 280 * _nss_ldap_passwd_constr is where life begins. This function calls the 281 * generic ldap constructor function to define and build the abstract 282 * data types required to support ldap operations. 283 */ 284 285 /*ARGSUSED0*/ 286 nss_backend_t * 287 _nss_ldap_shadow_constr(const char *dummy1, const char *dummy2, 288 const char *dummy3) 289 { 290 291 #ifdef DEBUG 292 (void) fprintf(stdout, "\n[getspent.c: _nss_ldap_shadow_constr]\n"); 293 #endif /* DEBUG */ 294 295 return ((nss_backend_t *)_nss_ldap_constr(sp_ops, 296 sizeof (sp_ops)/sizeof (sp_ops[0]), 297 _SHADOW, sp_attrs, _nss_ldap_shadow2ent)); 298 } 299