1131826Sharti/* $OpenBSD: groupaccess.c,v 1.16 2015/05/04 06:10:48 djm Exp $ */
2131826Sharti/*
3131826Sharti * Copyright (c) 2001 Kevin Steves.  All rights reserved.
4131826Sharti *
5131826Sharti * Redistribution and use in source and binary forms, with or without
6131826Sharti * modification, are permitted provided that the following conditions
7131826Sharti * are met:
8131826Sharti * 1. Redistributions of source code must retain the above copyright
9131826Sharti *    notice, this list of conditions and the following disclaimer.
10131826Sharti * 2. Redistributions in binary form must reproduce the above copyright
11131826Sharti *    notice, this list of conditions and the following disclaimer in the
12131826Sharti *    documentation and/or other materials provided with the distribution.
13131826Sharti *
14131826Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15131826Sharti * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16131826Sharti * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17131826Sharti * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18131826Sharti * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19131826Sharti * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20131826Sharti * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21131826Sharti * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22131826Sharti * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23131826Sharti * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24131826Sharti */
25131826Sharti
26131826Sharti#include "includes.h"
27131826Sharti
28131826Sharti#include <sys/types.h>
29131826Sharti
30131826Sharti#include <grp.h>
31131826Sharti#include <unistd.h>
32131826Sharti#include <stdarg.h>
33131826Sharti#include <stdlib.h>
34131826Sharti#include <string.h>
35131826Sharti#include <limits.h>
36131826Sharti
37131826Sharti#include "xmalloc.h"
38131826Sharti#include "groupaccess.h"
39131826Sharti#include "match.h"
40131826Sharti#include "log.h"
41131826Sharti
42131826Shartistatic int ngroups;
43131826Shartistatic char **groups_byname;
44131826Sharti
45131826Sharti/*
46131826Sharti * Initialize group access list for user with primary (base) and
47131826Sharti * supplementary groups.  Return the number of groups in the list.
48131826Sharti */
49131826Shartiint
50131826Shartiga_init(const char *user, gid_t base)
51131826Sharti{
52131826Sharti	gid_t *groups_bygid;
53131826Sharti	int i, j;
54131826Sharti	struct group *gr;
55131826Sharti
56131826Sharti	if (ngroups > 0)
57131826Sharti		ga_free();
58131826Sharti
59131826Sharti	ngroups = NGROUPS_MAX;
60131826Sharti#if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX)
61131826Sharti	ngroups = MAX(NGROUPS_MAX, sysconf(_SC_NGROUPS_MAX));
62131826Sharti#endif
63131826Sharti
64131826Sharti	groups_bygid = xcalloc(ngroups, sizeof(*groups_bygid));
65131826Sharti	groups_byname = xcalloc(ngroups, sizeof(*groups_byname));
66131826Sharti
67131826Sharti	if (getgrouplist(user, base, groups_bygid, &ngroups) == -1)
68131826Sharti		logit("getgrouplist: groups list too small");
69131826Sharti	for (i = 0, j = 0; i < ngroups; i++)
70131826Sharti		if ((gr = getgrgid(groups_bygid[i])) != NULL)
71131826Sharti			groups_byname[j++] = xstrdup(gr->gr_name);
72131826Sharti	free(groups_bygid);
73131826Sharti	return (ngroups = j);
74131826Sharti}
75131826Sharti
76131826Sharti/*
77131826Sharti * Return 1 if one of user's groups is contained in groups.
78131826Sharti * Return 0 otherwise.  Use match_pattern() for string comparison.
79131826Sharti */
80131826Shartiint
81131826Shartiga_match(char * const *groups, int n)
82131826Sharti{
83131826Sharti	int i, j;
84131826Sharti
85131826Sharti	for (i = 0; i < ngroups; i++)
86131826Sharti		for (j = 0; j < n; j++)
87131826Sharti			if (match_pattern(groups_byname[i], groups[j]))
88131826Sharti				return 1;
89131826Sharti	return 0;
90131826Sharti}
91131826Sharti
92131826Sharti/*
93131826Sharti * Return 1 if one of user's groups matches group_pattern list.
94131826Sharti * Return 0 on negated or no match.
95131826Sharti */
96131826Shartiint
97131826Shartiga_match_pattern_list(const char *group_pattern)
98131826Sharti{
99131826Sharti	int i, found = 0;
100131826Sharti
101131826Sharti	for (i = 0; i < ngroups; i++) {
102131826Sharti		switch (match_pattern_list(groups_byname[i], group_pattern, 0)) {
103131826Sharti		case -1:
104131826Sharti			return 0;	/* Negated match wins */
105131826Sharti		case 0:
106131826Sharti			continue;
107131826Sharti		case 1:
108131826Sharti			found = 1;
109131826Sharti		}
110131826Sharti	}
111131826Sharti	return found;
112131826Sharti}
113131826Sharti
114131826Sharti/*
115131826Sharti * Free memory allocated for group access list.
116131826Sharti */
117131826Shartivoid
118131826Shartiga_free(void)
119131826Sharti{
120131826Sharti	int i;
121131826Sharti
122131826Sharti	if (ngroups > 0) {
123131826Sharti		for (i = 0; i < ngroups; i++)
124131826Sharti			free(groups_byname[i]);
125131826Sharti		ngroups = 0;
126131826Sharti		free(groups_byname);
127131826Sharti	}
128131826Sharti}
129131826Sharti