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 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * 25 * getpwent.c 26 * 27 * lib/nsswitch/compat/getpwent.c -- name-service-switch backend for getpwnam() 28 * et al that does 4.x compatibility. It looks in /etc/passwd; if it finds 29 * passwd entries there that begin with "+" or "-", it consults other 30 * services. By default it uses NIS (YP), but the user can override this 31 * with a "passwd_compat" entry in /etc/nsswitch.conf, e.g. 32 * passwd_compat: nisplus 33 * 34 * This code tries to produce the same results as the 4.x code, even when 35 * the latter seems ill thought-out (mostly in the handling of netgroups, 36 * "-", and the combination thereof). Bug-compatible, in other words. 37 * Though we do try to be more reasonable about the format of "+" and "-" 38 * entries here, i.e. you don't have to pad them with spurious colons and 39 * bogus uid/gid values. 40 * 41 * Caveats: 42 * - More than one source may be specified, with the usual switch semantics, 43 * but having multiple sources here is definitely odd. 44 * - People who recursively specify "compat" deserve what they get. 45 * - Entries that begin with "+@" or "-@" are interpreted using 46 * getnetgrent() and innetgr(), which use the "netgroup" entry in 47 * /etc/nsswitch.conf. If the sources for "passwd_compat" and "netgroup" 48 * differ, everything should work fine, but the semantics will be pretty 49 * confusing. 50 */ 51 52 #pragma ident "%Z%%M% %I% %E% SMI" 53 54 #include <pwd.h> 55 #include <shadow.h> /* For PASSWD (pathname to passwd file) */ 56 #include <stdlib.h> 57 #include <strings.h> 58 #include "compat_common.h" 59 60 static DEFINE_NSS_DB_ROOT(db_root); 61 62 static void 63 _nss_initf_passwd_compat(p) 64 nss_db_params_t *p; 65 { 66 p->name = NSS_DBNAM_PASSWD; 67 p->config_name = NSS_DBNAM_PASSWD_COMPAT; 68 p->default_config = NSS_DEFCONF_PASSWD_COMPAT; 69 } 70 71 static const char * 72 get_pwname(argp) 73 nss_XbyY_args_t *argp; 74 { 75 struct passwd *p = (struct passwd *)argp->returnval; 76 77 return (p->pw_name); 78 } 79 80 static int 81 check_pwname(argp) 82 nss_XbyY_args_t *argp; 83 { 84 struct passwd *p = (struct passwd *)argp->returnval; 85 86 return (strcmp(p->pw_name, argp->key.name) == 0); 87 } 88 89 static nss_status_t 90 getbyname(be, a) 91 compat_backend_ptr_t be; 92 void *a; 93 { 94 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 95 96 return (_nss_compat_XY_all(be, argp, 97 check_pwname, NSS_DBOP_PASSWD_BYNAME)); 98 } 99 100 static int 101 check_pwuid(argp) 102 nss_XbyY_args_t *argp; 103 { 104 struct passwd *p = (struct passwd *)argp->returnval; 105 106 return (p->pw_uid == argp->key.uid); 107 } 108 109 static nss_status_t 110 getbyuid(be, a) 111 compat_backend_ptr_t be; 112 void *a; 113 { 114 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 115 116 return (_nss_compat_XY_all(be, argp, 117 check_pwuid, NSS_DBOP_PASSWD_BYUID)); 118 } 119 120 /*ARGSUSED*/ 121 static int 122 merge_pwents(be, argp, fields) 123 compat_backend_ptr_t be; 124 nss_XbyY_args_t *argp; 125 const char **fields; 126 { 127 struct passwd *pw = (struct passwd *)argp->buf.result; 128 char *buf = malloc(NSS_LINELEN_PASSWD); 129 char *s; 130 int parsestat; 131 int len; 132 int buflen; 133 134 if (buf == 0) { 135 return (NSS_STR_PARSE_PARSE); 136 /* Really "out of memory", but PARSE_PARSE will have to do */ 137 } 138 /* 139 * Don't allow overriding of 140 * - username 141 * - uid 142 * - gid 143 * That's what the SunOS 4.x code did; who are we to question it... 144 */ 145 s = buf; 146 buflen = argp->buf.buflen; 147 148 if (fields[1] != 0) 149 len = snprintf(s, buflen, "%s:%s", 150 pw->pw_name, fields[1]); 151 else { 152 /* ====> Does this do the right thing? */ 153 if (pw->pw_age != 0 && *pw->pw_age != '\0') 154 len = snprintf(s, buflen, "%s:%s,%s", 155 pw->pw_name, pw->pw_passwd, pw->pw_age); 156 else 157 len = snprintf(s, buflen, "%s:%s", 158 pw->pw_name, pw->pw_passwd); 159 } 160 161 if (len > buflen) 162 return (NSS_STR_PARSE_ERANGE); 163 164 s += len; 165 buflen -= len; 166 len = snprintf(s, buflen, ":%ld:%ld:%s:%s:%s", 167 pw->pw_uid, 168 pw->pw_gid, 169 fields[4] != 0 ? fields[4] : pw->pw_gecos, 170 fields[5] != 0 ? fields[5] : pw->pw_dir, 171 fields[6] != 0 ? fields[6] : pw->pw_shell); 172 173 if (len > buflen) 174 return (NSS_STR_PARSE_ERANGE); 175 176 s += len; 177 len = s - buf; 178 179 /* 180 * if asked, return the data in /etc file format 181 */ 182 if (be->return_string_data == 1) { 183 /* reset the result ptr to the original value */ 184 argp->buf.result = NULL; 185 186 if (len > argp->buf.buflen) { 187 parsestat = NSS_STR_PARSE_ERANGE; 188 } else { 189 (void) strncpy(argp->buf.buffer, buf, len); 190 argp->returnval = argp->buf.buffer; 191 argp->returnlen = len; 192 parsestat = NSS_SUCCESS; 193 } 194 } else { 195 parsestat = (*argp->str2ent)(buf, len, 196 argp->buf.result, 197 argp->buf.buffer, 198 argp->buf.buflen); 199 } 200 free(buf); 201 return (parsestat); 202 } 203 204 static compat_backend_op_t passwd_ops[] = { 205 _nss_compat_destr, 206 _nss_compat_endent, 207 _nss_compat_setent, 208 _nss_compat_getent, 209 getbyname, 210 getbyuid 211 }; 212 213 /*ARGSUSED*/ 214 nss_backend_t * 215 _nss_compat_passwd_constr(dummy1, dummy2, dummy3) 216 const char *dummy1, *dummy2, *dummy3; 217 { 218 return (_nss_compat_constr(passwd_ops, 219 sizeof (passwd_ops) / sizeof (passwd_ops[0]), 220 PASSWD, 221 NSS_LINELEN_PASSWD, 222 &db_root, 223 _nss_initf_passwd_compat, 224 1, 225 get_pwname, 226 merge_pwents)); 227 } 228