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