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