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, Version 1.0 only
   6  * (the "License").  You may not use this file except in compliance
   7  * with the License.
   8  *
   9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10  * or http://www.opensolaris.org/os/licensing.
  11  * See the License for the specific language governing permissions
  12  * and limitations under the License.
  13  *
  14  * When distributing Covered Code, include this CDDL HEADER in each
  15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16  * If applicable, add the following below this CDDL HEADER, with the
  17  * fields enclosed by brackets "[]" replaced with your own identifying
  18  * information: Portions Copyright [yyyy] [name of copyright owner]
  19  *
  20  * CDDL HEADER END
  21  */
  22 
  23 /*
  24  * Copyright (c) 1996, by Sun Microsystems, Inc.
  25  * All rights reserved.
  26  *
  27  * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
  28  */
  29 
  30 #include <stdlib.h>
  31 #include <stdio.h>
  32 #include <ctype.h>
  33 #include <string.h>
  34 #include "table.h"
  35 #include "util.h"
  36 #include "getgroup.h"
  37 
  38 /*
  39  * Stolen mostly, from getnetgrent.c
  40  *
  41  * my_getgroup() performs the same function as _getgroup(), but operates
  42  * on /etc/netgroup directly, rather than doing yp lookups.
  43  *
  44  * /etc/netgroup must first loaded into a hash table so the matching
  45  * function can look up lines quickly.
  46  */
  47 
  48 
  49 /* To check for cycles in netgroups */
  50 struct list {
  51         char *name;
  52         struct list *nxt;
  53 };
  54 
  55 static char *any();
  56 static char *match();
  57 static char *fill();
  58 
  59 
  60 void
  61 freegrouplist(revhandle_t *hdl)
  62 {
  63         struct grouplist *gl, *next;
  64 
  65         for (gl = hdl->grouplist; gl != NULL; gl = next) {
  66                 next = gl->gl_nxt;
  67 
  68                 FREE(gl->gl_name);
  69                 FREE(gl->gl_domain);
  70                 FREE(gl->gl_machine);
  71                 FREE(gl);
  72         }
  73         hdl->grouplist = NULL;
  74 }
  75 
  76 
  77 
  78 /*
  79  * recursive function to find the members of netgroup "group". "list" is
  80  * the path followed through the netgroups so far, to check for cycles.
  81  */
  82 void
  83 doit(char *group, struct list *list, revhandle_t *hdl)
  84 {
  85         register char *p, *q;
  86         register struct list *ls;
  87         struct list tmplist;
  88         char *val;
  89         struct grouplist *gpls;
  90 
  91 
  92         /*
  93          * check for non-existing groups
  94          */
  95         if ((val = match(group, hdl)) == NULL) {
  96                 return;
  97         }
  98 
  99 
 100         /*
 101          * check for cycles
 102          */
 103         for (ls = list; ls != NULL; ls = ls->nxt) {
 104                 if (strcmp(ls->name, group) == 0) {
 105                         (void) fprintf(stderr,
 106                             "Cycle detected in /etc/netgroup: %s.\n",
 107                             group);
 108                         return;
 109                 }
 110         }
 111 
 112 
 113         ls = &tmplist;
 114         ls->name = group;
 115         ls->nxt = list;
 116         list = ls;
 117 
 118         p = val;
 119         while (p != NULL) {
 120                 while (*p == ' ' || *p == '\t')
 121                         p++;
 122                 if (*p == EOS || *p == '#')
 123                         break;
 124                 if (*p == '(') {
 125                         gpls = MALLOC(struct grouplist);
 126                         p++;
 127 
 128                         if (!(p = fill(p, &gpls->gl_machine, ',')))  {
 129                                 goto syntax_error;
 130                         }
 131                         if (!(p = fill(p, &gpls->gl_name, ','))) {
 132                                 goto syntax_error;
 133                         }
 134                         if (!(p = fill(p, &gpls->gl_domain, ')'))) {
 135                                 goto syntax_error;
 136                         }
 137                         gpls->gl_nxt = hdl->grouplist;
 138                         hdl->grouplist = gpls;
 139                 } else {
 140                         q = any(p, " \t\n#");
 141                         if (q && *q == '#')
 142                                 break;
 143                         *q = EOS;
 144                         doit(p, list, hdl);
 145                         *q = ' ';
 146                 }
 147                 p = any(p, " \t");
 148         }
 149         return;
 150 
 151 syntax_error:
 152         (void) fprintf(stderr, "syntax error in /etc/netgroup\n");
 153         (void) fprintf(stderr, "--- %s %s\n", group, val);
 154 }
 155 
 156 
 157 
 158 
 159 /*
 160  * Fill a buffer "target" selectively from buffer "start".
 161  * "termchar" terminates the information in start, and preceding
 162  * or trailing white space is ignored.  If the buffer "start" is
 163  * empty, "target" is filled with "*". The location just after the
 164  * terminating character is returned.
 165  */
 166 static char *
 167 fill(start, target, termchar)
 168         char *start;
 169         char **target;
 170         char termchar;
 171 {
 172         register char *p;
 173         register char *q;
 174         register char *r;
 175         int size;
 176 
 177         for (p = start; *p == ' ' || *p == '\t'; p++)
 178                 ;
 179         r = strchr(p, termchar);
 180         if (r == (char *)NULL) {
 181                 return ((char *)NULL);
 182         }
 183         if (p == r) {
 184                 *target = NULL;
 185         } else {
 186                 for (q = r-1; *q == ' ' || *q == '\t'; q--)
 187                         ;
 188                 size = q-p+1;
 189                 STRNCPY(*target, p, size);
 190         }
 191         return (r+1);
 192 }
 193 
 194 
 195 /*
 196  * scans cp, looking for a match with any character
 197  * in match.  Returns pointer to place in cp that matched
 198  * (or NULL if no match)
 199  */
 200 static char *
 201 any(cp, match)
 202         register char *cp;
 203         char *match;
 204 {
 205         register char *mp, c;
 206 
 207         while (c = *cp) {
 208                 for (mp = match; *mp; mp++)
 209                         if (*mp == c)
 210                                 return (cp);
 211                 cp++;
 212         }
 213         return (NULL);
 214 }
 215 
 216 
 217 
 218 /*
 219  * The equivalent of yp_match. Returns the match, or NULL if there is none.
 220  */
 221 static char *
 222 match(char *group, revhandle_t *hdl)
 223 {
 224         return (lookup(hdl->ngtable, group));
 225 }