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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <stdlib.h> 27 #include "files_common.h" 28 #include <time.h> 29 #include <exec_attr.h> 30 #include <strings.h> 31 #include <sys/stat.h> 32 #include <sys/mman.h> 33 #include <ctype.h> 34 #include <synch.h> 35 #include <sys/types.h> 36 #include <sys/uio.h> 37 #include <unistd.h> 38 39 /* 40 * files/getexecattr.c -- "files" backend for nsswitch "exec_attr" database 41 * 42 * _execattr_files_read_line and _execattr_files_XY_all code based on 43 * nss_files_read_line and nss_files_XY_all respectively, from files_common.c 44 */ 45 46 47 /* externs from libnsl */ 48 extern int _doexeclist(nss_XbyY_args_t *); 49 extern int _readbufline(char *, int, char *, int, int *); 50 extern char *_exec_wild_id(char *, const char *); 51 extern void _exec_cleanup(nss_status_t, nss_XbyY_args_t *); 52 53 54 /* 55 * check_match: returns 1 if matching entry found, else returns 0. 56 */ 57 static int 58 check_match(nss_XbyY_args_t *argp, const char *line, int linelen) 59 { 60 const char *limit, *linep, *keyp; 61 _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp); 62 const char *exec_field[6]; 63 int i; 64 65 exec_field[0] = _priv_exec->name; /* name */ 66 exec_field[1] = _priv_exec->policy; /* policy */ 67 exec_field[2] = _priv_exec->type; /* type */ 68 exec_field[3] = NULL; /* res1 */ 69 exec_field[4] = NULL; /* res2 */ 70 exec_field[5] = _priv_exec->id; /* id */ 71 /* No need to check attr field */ 72 73 linep = line; 74 limit = line + linelen; 75 76 for (i = 0; i < 6; i++) { 77 keyp = exec_field[i]; 78 if (keyp) { 79 /* compare field */ 80 while (*keyp && linep < limit && 81 *linep != ':' && *keyp == *linep) { 82 keyp++; 83 linep++; 84 } 85 if (*keyp || linep == limit || *linep != ':') 86 return (0); 87 } else { 88 /* skip field */ 89 while (linep < limit && *linep != ':') 90 linep++; 91 } 92 linep++; 93 } 94 return (1); 95 } 96 97 98 static nss_status_t 99 _exec_files_XY_all(files_backend_ptr_t be, 100 nss_XbyY_args_t *argp, 101 int getby_flag) 102 { 103 int parse_stat = 0; 104 int lastlen = 0; 105 int exec_fd = 0; 106 int f_size = 0; 107 time_t f_time = 0; 108 static time_t read_time = 0; 109 char *first; 110 char *last; 111 static char *f_buf = NULL; 112 struct stat f_stat; 113 nss_status_t res = NSS_NOTFOUND; 114 _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp); 115 static rwlock_t exec_lock; 116 117 if (((be->buf == NULL) && 118 ((be->buf = (char *)calloc(1, be->minbuf)) == NULL)) || 119 (be->filename == NULL) || 120 (rw_rdlock(&exec_lock) != 0)) { 121 return (NSS_UNAVAIL); 122 } 123 124 /* 125 * check the size and the time stamp on the file 126 */ 127 if (stat(be->filename, &f_stat) != 0) { 128 (void) _nss_files_endent(be, 0); 129 (void) rw_unlock(&exec_lock); 130 return (NSS_UNAVAIL); 131 } 132 133 f_size = f_stat.st_size; 134 f_time = f_stat.st_mtime; 135 136 while (f_time > read_time) { 137 /* 138 * file has been modified since we last read it. 139 * read it into the buffer with rw lock. 140 */ 141 (void) rw_unlock(&exec_lock); 142 if (rw_wrlock(&exec_lock) != 0) { 143 (void) _nss_files_endent(be, 0); 144 return (NSS_UNAVAIL); 145 } 146 if ((be->f = fopen(be->filename, "rF")) == 0) { 147 (void) _nss_files_endent(be, 0); 148 (void) rw_unlock(&exec_lock); 149 return (NSS_UNAVAIL); 150 } 151 exec_fd = fileno(be->f); 152 if (f_buf != NULL) 153 free(f_buf); 154 if ((f_buf = malloc(f_size)) == NULL) { 155 (void) _nss_files_endent(be, 0); 156 (void) rw_unlock(&exec_lock); 157 return (NSS_UNAVAIL); 158 } 159 if (read(exec_fd, f_buf, f_size) < f_size) { 160 free(f_buf); 161 (void) _nss_files_endent(be, 0); 162 (void) rw_unlock(&exec_lock); 163 return (NSS_UNAVAIL); 164 } 165 read_time = f_time; 166 (void) rw_unlock(&exec_lock); 167 /* 168 * verify that the file did not change after 169 * we read it. 170 */ 171 if (rw_rdlock(&exec_lock) != 0) { 172 free(f_buf); 173 (void) _nss_files_endent(be, 0); 174 return (NSS_UNAVAIL); 175 } 176 if (stat(be->filename, &f_stat) != 0) { 177 free(f_buf); 178 (void) _nss_files_endent(be, 0); 179 (void) rw_unlock(&exec_lock); 180 return (NSS_UNAVAIL); 181 } 182 f_size = f_stat.st_size; 183 f_time = f_stat.st_mtime; 184 } 185 186 res = NSS_NOTFOUND; 187 /*CONSTCOND*/ 188 while (1) { 189 int linelen = 0; 190 char *instr = be->buf; 191 192 linelen = _readbufline(f_buf, f_size, instr, be->minbuf, 193 &lastlen); 194 if (linelen < 0) { 195 /* End of file */ 196 break; 197 } 198 199 /* 200 * If the entry doesn't contain the filter string then 201 * it can't be the entry we want, so don't bother looking 202 * more closely at it. 203 */ 204 switch (getby_flag) { 205 case NSS_DBOP_EXECATTR_BYNAME: 206 if (strstr(instr, _priv_exec->name) == NULL) 207 continue; 208 break; 209 case NSS_DBOP_EXECATTR_BYID: 210 if (strstr(instr, _priv_exec->id) == NULL) 211 continue; 212 break; 213 case NSS_DBOP_EXECATTR_BYNAMEID: 214 if ((strstr(instr, _priv_exec->name) == NULL) || 215 (strstr(instr, _priv_exec->id) == NULL)) 216 continue; 217 break; 218 default: 219 break; 220 } 221 if (((_priv_exec->policy != NULL) && 222 (strstr(instr, _priv_exec->policy) == NULL)) || 223 ((_priv_exec->type != NULL) && 224 (strstr(instr, _priv_exec->type) == NULL))) 225 continue; 226 227 /* 228 * Get rid of white spaces, comments etc. 229 */ 230 if ((last = strchr(instr, '#')) == NULL) 231 last = instr + linelen; 232 *last-- = '\0'; /* Nuke '\n' or #comment */ 233 /* 234 * Skip leading whitespace. Normally there isn't any, 235 * so it's not worth calling strspn(). 236 */ 237 for (first = instr; isspace(*first); first++) 238 ; 239 if (*first == '\0') 240 continue; 241 /* 242 * Found something non-blank on the line. Skip back 243 * over any trailing whitespace; since we know there's 244 * non-whitespace earlier in the line, checking for 245 * termination is easy. 246 */ 247 while (isspace(*last)) 248 --last; 249 linelen = last - first + 1; 250 if (first != instr) 251 instr = first; 252 253 /* Check the entry */ 254 argp->returnval = NULL; 255 argp->returnlen = 0; 256 if (check_match(argp, instr, linelen) == 0) 257 continue; 258 259 /* Marshall the data */ 260 parse_stat = (*argp->str2ent)(instr, linelen, argp->buf.result, 261 argp->buf.buffer, argp->buf.buflen); 262 if (parse_stat == NSS_STR_PARSE_SUCCESS) { 263 argp->returnval = (argp->buf.result != NULL)? 264 argp->buf.result : argp->buf.buffer; 265 argp->returnlen = linelen; 266 res = NSS_SUCCESS; 267 if (IS_GET_ONE(_priv_exec->search_flag)) { 268 break; 269 } else if (_doexeclist(argp) == 0) { 270 res = NSS_UNAVAIL; 271 break; 272 } 273 } else if (parse_stat == NSS_STR_PARSE_ERANGE) { 274 argp->erange = 1; 275 break; 276 } /* else if (parse_stat == NSS_STR_PARSE_PARSE) don't care ! */ 277 } 278 279 (void) _nss_files_endent(be, 0); 280 (void) rw_unlock(&exec_lock); 281 282 return (res); 283 } 284 285 286 /* 287 * If search for exact match for id failed, get_wild checks if we have 288 * a wild-card entry for that id. 289 */ 290 static nss_status_t 291 get_wild(files_backend_ptr_t be, nss_XbyY_args_t *argp, int getby_flag) 292 { 293 const char *orig_id = NULL; 294 char *old_id = NULL; 295 char *wild_id = NULL; 296 nss_status_t res = NSS_NOTFOUND; 297 _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp); 298 299 orig_id = _priv_exec->id; 300 old_id = strdup(_priv_exec->id); 301 wild_id = old_id; 302 while ((wild_id = _exec_wild_id(wild_id, _priv_exec->type)) != NULL) { 303 _priv_exec->id = wild_id; 304 res = _exec_files_XY_all(be, argp, getby_flag); 305 if (res == NSS_SUCCESS) 306 break; 307 } 308 _priv_exec->id = orig_id; 309 if (old_id) 310 free(old_id); 311 312 return (res); 313 } 314 315 316 static nss_status_t 317 getbynam(files_backend_ptr_t be, void *a) 318 { 319 nss_status_t res; 320 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 321 322 res = _exec_files_XY_all(be, argp, NSS_DBOP_EXECATTR_BYNAME); 323 324 _exec_cleanup(res, argp); 325 326 return (res); 327 } 328 329 330 static nss_status_t 331 getbyid(files_backend_ptr_t be, void *a) 332 { 333 nss_status_t res; 334 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 335 /*LINTED*/ 336 _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp); 337 338 res = _exec_files_XY_all(be, argp, NSS_DBOP_EXECATTR_BYID); 339 340 if (res != NSS_SUCCESS) 341 res = get_wild(be, argp, NSS_DBOP_EXECATTR_BYID); 342 343 _exec_cleanup(res, argp); 344 345 return (res); 346 } 347 348 349 static nss_status_t 350 getbynameid(files_backend_ptr_t be, void *a) 351 { 352 nss_status_t res; 353 nss_XbyY_args_t *argp = (nss_XbyY_args_t *)a; 354 /*LINTED*/ 355 _priv_execattr *_priv_exec = (_priv_execattr *)(argp->key.attrp); 356 357 res = _exec_files_XY_all(be, argp, NSS_DBOP_EXECATTR_BYNAMEID); 358 359 if (res != NSS_SUCCESS) 360 res = get_wild(be, argp, NSS_DBOP_EXECATTR_BYNAMEID); 361 362 _exec_cleanup(res, argp); 363 364 return (res); 365 } 366 367 368 static files_backend_op_t execattr_ops[] = { 369 _nss_files_destr, 370 _nss_files_endent, 371 _nss_files_setent, 372 _nss_files_getent_netdb, 373 getbynam, 374 getbyid, 375 getbynameid 376 }; 377 378 /*ARGSUSED*/ 379 nss_backend_t * 380 _nss_files_exec_attr_constr(const char *dummy1, 381 const char *dummy2, 382 const char *dummy3, 383 const char *dummy4, 384 const char *dummy5, 385 const char *dummy6, 386 const char *dummy7) 387 { 388 return (_nss_files_constr(execattr_ops, 389 sizeof (execattr_ops)/sizeof (execattr_ops[0]), 390 EXECATTR_FILENAME, NSS_LINELEN_EXECATTR, NULL)); 391 } 392