/* $OpenBSD: groupaccess.c,v 1.16 2015/05/04 06:10:48 djm Exp $ */ /* * Copyright (c) 2001 Kevin Steves. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" #include #include #include #include #include #include #include #ifdef WINDOWS #include #include #endif #include "xmalloc.h" #include "groupaccess.h" #include "match.h" #include "log.h" static int ngroups; static char **groups_byname; /* * Initialize group access list for user with primary (base) and * supplementary groups. Return the number of groups in the list. */ int ga_init(const char *user, gid_t base) { #ifdef WINDOWS #pragma warning(push, 3) LPLOCALGROUP_USERS_INFO_0 local_groups_info = NULL, tmp_groups_info; wchar_t *user_utf16 = NULL, *full_name_utf16 = NULL, *udom_utf16 = NULL, *tmp; char *group_utf8 = NULL; DWORD i = 0, j = 0; DWORD entries_read = 0, total_entries = 0, full_name_len = 0, index = 0; NET_API_STATUS nStatus; if (ngroups > 0) ga_free(); if ((user_utf16 = utf8_to_utf16(user)) == NULL) { errno = ENOMEM; goto done; } full_name_len = (DWORD)wcslen(user_utf16) + 1; if ((full_name_utf16 = malloc(full_name_len * sizeof(wchar_t))) == NULL) { errno = ENOMEM; goto done; } if ((tmp = wcschr(user_utf16, L'@')) != NULL) { udom_utf16 = tmp + 1; *tmp = L'\0'; index = (DWORD)wcslen(udom_utf16) + 1; wmemcpy(full_name_utf16, udom_utf16, index); full_name_utf16[wcslen(udom_utf16)] = L'\\'; } wmemcpy(full_name_utf16 + index, user_utf16, wcslen(user_utf16) + 1); nStatus = NetUserGetLocalGroups(NULL, full_name_utf16, 0, LG_INCLUDE_INDIRECT, (LPBYTE *)&local_groups_info, MAX_PREFERRED_LENGTH, &entries_read, &total_entries); if (NERR_Success != nStatus) { error("NetUserGetLocalGroups() failed with error: %u", nStatus); errno = ENOENT; goto done; } if (entries_read != total_entries) { error("NetUserGetLocalGroups(): entries_read (%u) is not equal to " "total_entries (%u) for user %.100s", entries_read, total_entries, user); errno = ENOENT; goto done; } if ((tmp_groups_info = local_groups_info) != NULL) { groups_byname = xcalloc(entries_read, sizeof(*groups_byname)); for (i = 0, j = 0; i < total_entries; i++) { if ((group_utf8 = utf16_to_utf8(tmp_groups_info->lgrui0_name)) == NULL) { errno = ENOMEM; goto done; } groups_byname[j++] = group_utf8; tmp_groups_info++; } } done: if(user_utf16 != NULL) free(user_utf16); if(full_name_utf16 != NULL) free(full_name_utf16); if (local_groups_info != NULL) NetApiBufferFree(local_groups_info); #pragma warning(pop) #else /* !WINDOWS */ gid_t *groups_bygid; int i, j; struct group *gr; if (ngroups > 0) ga_free(); ngroups = NGROUPS_MAX; #if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX) ngroups = MAX(NGROUPS_MAX, sysconf(_SC_NGROUPS_MAX)); #endif groups_bygid = xcalloc(ngroups, sizeof(*groups_bygid)); groups_byname = xcalloc(ngroups, sizeof(*groups_byname)); if (getgrouplist(user, base, groups_bygid, &ngroups) == -1) logit("getgrouplist: groups list too small"); for (i = 0, j = 0; i < ngroups; i++) if ((gr = getgrgid(groups_bygid[i])) != NULL) groups_byname[j++] = xstrdup(gr->gr_name); free(groups_bygid); #endif /* !WINDOWS */ return (ngroups = j); } /* * Return 1 if one of user's groups is contained in groups. * Return 0 otherwise. Use match_pattern() for string comparison. */ int ga_match(char * const *groups, int n) { int i, j; for (i = 0; i < ngroups; i++) for (j = 0; j < n; j++) if (match_pattern(groups_byname[i], groups[j])) return 1; return 0; } /* * Return 1 if one of user's groups matches group_pattern list. * Return 0 on negated or no match. */ int ga_match_pattern_list(const char *group_pattern) { int i, found = 0; for (i = 0; i < ngroups; i++) { switch (match_pattern_list(groups_byname[i], group_pattern, 0)) { case -1: return 0; /* Negated match wins */ case 0: continue; case 1: found = 1; } } return found; } /* * Free memory allocated for group access list. */ void ga_free(void) { int i; if (ngroups > 0) { for (i = 0; i < ngroups; i++) free(groups_byname[i]); ngroups = 0; free(groups_byname); } }