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 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #pragma weak setspent = _setspent 29 #pragma weak endspent = _endspent 30 #pragma weak getspnam_r = _getspnam_r 31 #pragma weak getspent_r = _getspent_r 32 #pragma weak fgetspent_r = _fgetspent_r 33 34 #include "synonyms.h" 35 #include <mtlib.h> 36 #include <sys/types.h> 37 #include <shadow.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <nss_dbdefs.h> 41 #include <stdio.h> 42 #include <synch.h> 43 44 int str2spwd(const char *, int, void *, 45 char *, int); 46 47 static DEFINE_NSS_DB_ROOT(db_root); 48 static DEFINE_NSS_GETENT(context); 49 50 void 51 _nss_initf_shadow(nss_db_params_t *p) 52 { 53 p->name = NSS_DBNAM_SHADOW; 54 p->config_name = NSS_DBNAM_PASSWD; /* Use config for "passwd" */ 55 p->default_config = NSS_DEFCONF_PASSWD; 56 } 57 58 struct spwd * 59 getspnam_r(const char *name, struct spwd *result, char *buffer, int buflen) 60 { 61 nss_XbyY_args_t arg; 62 63 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2spwd); 64 arg.key.name = name; 65 (void) nss_search(&db_root, _nss_initf_shadow, \ 66 NSS_DBOP_SHADOW_BYNAME, &arg); 67 return ((struct spwd *)NSS_XbyY_FINI(&arg)); 68 } 69 70 void 71 setspent(void) 72 { 73 nss_setent(&db_root, _nss_initf_shadow, &context); 74 } 75 76 void 77 endspent(void) 78 { 79 nss_endent(&db_root, _nss_initf_shadow, &context); 80 nss_delete(&db_root); 81 } 82 83 struct spwd * 84 getspent_r(struct spwd *result, char *buffer, int buflen) 85 { 86 nss_XbyY_args_t arg; 87 char *nam; 88 89 /* In getXXent_r(), protect the unsuspecting caller from +/- entries */ 90 91 do { 92 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2spwd); 93 /* No key to fill in */ 94 (void) nss_getent(&db_root, _nss_initf_shadow, &context, &arg); 95 } while (arg.returnval != 0 && 96 (nam = ((struct spwd *)arg.returnval)->sp_namp) != 0 && 97 (*nam == '+' || *nam == '-')); 98 99 return (struct spwd *)NSS_XbyY_FINI(&arg); 100 } 101 102 struct spwd * 103 fgetspent_r(FILE *f, struct spwd *result, char *buffer, int buflen) 104 { 105 extern void _nss_XbyY_fgets(FILE *, nss_XbyY_args_t *); 106 nss_XbyY_args_t arg; 107 108 /* ... but in fgetXXent_r, the caller deserves any +/- entry he gets */ 109 110 /* No key to fill in */ 111 NSS_XbyY_INIT(&arg, result, buffer, buflen, str2spwd); 112 _nss_XbyY_fgets(f, &arg); 113 return (struct spwd *)NSS_XbyY_FINI(&arg); 114 } 115 116 typedef const char *constp; 117 118 static int /* 1 means success and more input, 0 means error or no more */ 119 getfield(constp *nextp, constp limit, int uns, void *valp) 120 { 121 constp p = *nextp; 122 char *endfield; 123 char numbuf[12]; /* Holds -2^31 and trailing ':' */ 124 size_t len; 125 126 if (p == 0 || p >= limit) { 127 return (0); 128 } 129 if (*p == ':') { 130 p++; 131 *nextp = p; 132 return (p < limit); 133 } 134 if ((len = limit - p) > sizeof (numbuf) - 1) { 135 len = sizeof (numbuf) - 1; 136 } 137 /* 138 * We want to use strtol() and we have a readonly non-zero-terminated 139 * string, so first we copy and terminate the interesting bit. 140 * Ugh. (It's convenient to terminate with a colon rather than \0). 141 */ 142 if ((endfield = memccpy(numbuf, p, ':', len)) == 0) { 143 if (len != limit - p) { 144 /* Error -- field is too big to be a legit number */ 145 return (0); 146 } 147 numbuf[len] = ':'; 148 p = limit; 149 } else { 150 p += (endfield - numbuf); 151 } 152 if (uns) { 153 unsigned long ux = strtoul(numbuf, &endfield, 10); 154 if (*endfield != ':') { 155 /* Error -- expected <integer><colon> */ 156 return (0); 157 } 158 *((unsigned int *)valp) = (unsigned int)ux; 159 } else { 160 long x = strtol(numbuf, &endfield, 10); 161 if (*endfield != ':') { 162 /* Error -- expected <integer><colon> */ 163 return (0); 164 } 165 *((int *)valp) = (int)x; 166 } 167 *nextp = p; 168 return (p < limit); 169 } 170 171 /* 172 * str2spwd() -- convert a string to a shadow passwd entry. The parser is 173 * more liberal than the passwd or group parsers; since it's legitimate 174 * for almost all the fields here to be blank, the parser lets one omit 175 * any number of blank fields at the end of the entry. The acceptable 176 * forms for '+' and '-' entries are the same as those for normal entries. 177 * === Is this likely to do more harm than good? 178 * 179 * Return values: 0 = success, 1 = parse error, 2 = erange ... 180 * The structure pointer passed in is a structure in the caller's space 181 * wherein the field pointers would be set to areas in the buffer if 182 * need be. instring and buffer should be separate areas. 183 */ 184 int 185 str2spwd(const char *instr, int lenstr, void *ent, char *buffer, int buflen) 186 { 187 struct spwd *shadow = (struct spwd *)ent; 188 const char *p = instr, *limit; 189 char *bufp; 190 int black_magic; 191 size_t lencopy; 192 193 limit = p + lenstr; 194 if ((p = memchr(instr, ':', lenstr)) == 0 || 195 ++p >= limit || 196 (p = memchr(p, ':', limit - p)) == 0) { 197 lencopy = (size_t)lenstr; 198 p = 0; 199 } else { 200 lencopy = p - instr; 201 p++; 202 } 203 if (lencopy + 1 > buflen) { 204 return (NSS_STR_PARSE_ERANGE); 205 } 206 207 if (instr != buffer) { 208 /* Overlapping buffer copies are OK */ 209 (void) memmove(buffer, instr, lencopy); 210 buffer[lencopy] = 0; 211 } 212 213 /* quick exit do not entry fill if not needed */ 214 if (ent == (void *)NULL) 215 return (NSS_STR_PARSE_SUCCESS); 216 217 black_magic = (*instr == '+' || *instr == '-'); 218 shadow->sp_namp = bufp = buffer; 219 shadow->sp_pwdp = 0; 220 shadow->sp_lstchg = -1; 221 shadow->sp_min = -1; 222 shadow->sp_max = -1; 223 shadow->sp_warn = -1; 224 shadow->sp_inact = -1; 225 shadow->sp_expire = -1; 226 shadow->sp_flag = 0; 227 228 if ((bufp = strchr(bufp, ':')) == 0) { 229 if (black_magic) 230 return (NSS_STR_PARSE_SUCCESS); 231 else 232 return (NSS_STR_PARSE_PARSE); 233 } 234 *bufp++ = '\0'; 235 236 shadow->sp_pwdp = bufp; 237 if (instr == 0) { 238 if ((bufp = strchr(bufp, ':')) == 0) { 239 if (black_magic) 240 return (NSS_STR_PARSE_SUCCESS); 241 else 242 return (NSS_STR_PARSE_PARSE); 243 } 244 *bufp++ = '\0'; 245 p = bufp; 246 } /* else p was set when we copied name and passwd into the buffer */ 247 248 if (!getfield(&p, limit, 0, &shadow->sp_lstchg)) 249 return (NSS_STR_PARSE_SUCCESS); 250 if (!getfield(&p, limit, 0, &shadow->sp_min)) 251 return (NSS_STR_PARSE_SUCCESS); 252 if (!getfield(&p, limit, 0, &shadow->sp_max)) 253 return (NSS_STR_PARSE_SUCCESS); 254 if (!getfield(&p, limit, 0, &shadow->sp_warn)) 255 return (NSS_STR_PARSE_SUCCESS); 256 if (!getfield(&p, limit, 0, &shadow->sp_inact)) 257 return (NSS_STR_PARSE_SUCCESS); 258 if (!getfield(&p, limit, 0, &shadow->sp_expire)) 259 return (NSS_STR_PARSE_SUCCESS); 260 if (!getfield(&p, limit, 1, &shadow->sp_flag)) 261 return (NSS_STR_PARSE_SUCCESS); 262 if (p != limit) { 263 /* Syntax error -- garbage at end of line */ 264 return (NSS_STR_PARSE_PARSE); 265 } 266 return (NSS_STR_PARSE_SUCCESS); 267 } 268