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