/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pwd.h>
#include <string.h>
#include <deflt.h>
#include <libintl.h>
#include <locale.h>
#include <user_attr.h>
#include <prof_attr.h>
#include <auth_attr.h>
#define EXIT_OK 0
#define EXIT_FATAL 1
#define EXIT_NON_FATAL 2
#ifndef TEXT_DOMAIN /* Should be defined by cc -D */
#define TEXT_DOMAIN "SYS_TEST"
#endif
#define INCRAUTHS 512
typedef struct cbs {
int auth_cnt;
int auth_max;
char **auths;
} cbs_t;
static int show_auths(char *, int);
static int add_auth(const char *, void *, void *);
static void free_auths(cbs_t *);
static void simplify(cbs_t *);
static char *progname = "auths";
int
main(int argc, char *argv[])
{
int status = EXIT_OK;
(void) setlocale(LC_ALL, "");
(void) textdomain(TEXT_DOMAIN);
switch (argc) {
case 1:
status = show_auths(NULL, 0);
break;
case 2:
status = show_auths(argv[argc-1], 0);
break;
default:
while (*++argv) {
status = show_auths(*argv, 1);
if (status == EXIT_FATAL) {
break;
}
}
break;
}
status = (status == EXIT_OK) ? status : EXIT_FATAL;
return (status);
}
static int
show_auths(char *username, int print_name)
{
int status = EXIT_OK;
struct passwd *pw;
int i;
cbs_t cbs = { 0, 0, NULL };
if (username == NULL) {
if ((pw = getpwuid(getuid())) == NULL) {
status = EXIT_NON_FATAL;
(void) fprintf(stderr, "%s: ", progname);
(void) fprintf(stderr, gettext("No passwd entry\n"));
return (status);
}
username = pw->pw_name;
} else if (getpwnam(username) == NULL) {
status = EXIT_NON_FATAL;
(void) fprintf(stderr, "%s: %s : ", progname, username);
(void) fprintf(stderr, gettext("No such user\n"));
return (status);
}
(void) _enum_auths(username, add_auth, NULL, &cbs);
if (cbs.auth_cnt == 0)
status = EXIT_NON_FATAL;
if (status == EXIT_NON_FATAL) {
(void) fprintf(stderr, "%s: %s: ", progname, username);
(void) fprintf(stderr, gettext("No authorizations\n"));
} else {
simplify(&cbs);
if (print_name)
(void) printf("%s: ", username);
/* print out the auths */
for (i = 0; i < cbs.auth_cnt - 1; i++)
(void) printf("%s,", cbs.auths[i]);
/* print out the last entry, without the comma */
(void) printf("%s\n", cbs.auths[cbs.auth_cnt - 1]);
/* free memory allocated for authorizations */
free_auths(&cbs);
}
return (status);
}
/*ARGSUSED*/
static int
add_auth(const char *authname, void *ctxt, void *res)
{
cbs_t *cbs = res;
if (cbs->auth_cnt >= cbs->auth_max) {
cbs->auth_max += INCRAUTHS;
cbs->auths = realloc(cbs->auths,
cbs->auth_max * sizeof (char *));
if (cbs->auths == NULL) {
(void) fprintf(stderr, "%s: ", progname);
(void) fprintf(stderr, gettext("Out of memory\n"));
exit(1);
}
}
cbs->auths[cbs->auth_cnt] = strdup(authname);
cbs->auth_cnt++;
return (0);
}
static void
free_auths(cbs_t *cbs)
{
int i;
for (i = 0; i < cbs->auth_cnt; i++)
free(cbs->auths[i]);
free(cbs->auths);
}
/* We have always ignored .grant in auths(1) */
static boolean_t
auth_match(const char *pattern, const char *auth)
{
size_t len = strlen(pattern);
if (pattern[len - 1] != KV_WILDCHAR)
return (B_FALSE);
return (strncmp(pattern, auth, len - 1) == 0);
}
static int
mstrptr(const void *a, const void *b)
{
char *const *ap = a;
char *const *bp = b;
return (strcmp(*ap, *bp));
}
/*
* Simplify the returned authorizations: sort and match wildcards;
* we're using here that "*" sorts before any other character.
*/
static void
simplify(cbs_t *cbs)
{
int rem, i;
/* First we sort */
qsort(cbs->auths, cbs->auth_cnt, sizeof (cbs->auths[0]), mstrptr);
/*
* Then we remove the entries which match a later entry.
* We walk the list, with "i + rem + 1" the cursor for the possible
* candidate for removal. With "rem" we count the removed entries
* and we copy while we're looking for duplicate/superfluous entries.
*/
for (i = 0, rem = 0; i < cbs->auth_cnt - rem - 1; ) {
if (strcmp(cbs->auths[i], cbs->auths[i + rem + 1]) == 0 ||
strchr(cbs->auths[i], KV_WILDCHAR) != NULL &&
auth_match(cbs->auths[i], cbs->auths[i + rem + 1])) {
free(cbs->auths[i + rem + 1]);
rem++;
} else {
i++;
if (rem > 0)
cbs->auths[i] = cbs->auths[i + rem];
}
}
cbs->auth_cnt -= rem;
}