1/*	$NetBSD: user_acl.c,v 1.2 2017/02/14 01:16:45 christos Exp $	*/
2
3/*++
4/* NAME
5/*	user_acl 3
6/* SUMMARY
7/*	user name based access control
8/* SYNOPSIS
9/*	#include <user_acl.h>
10/*
11/*	const char *check_user_acl_byuid(pname, acl, uid)
12/*	const char *pname;
13/*	const char *acl;
14/*	uid_t	uid;
15/* DESCRIPTION
16/*	check_user_acl_byuid() converts the given uid into a user
17/*	name, and checks the result against a user name matchlist.
18/*	If the uid cannot be resolved to a user name, "unknown"
19/*	is used as the lookup key instead.
20/*	The result is NULL on success, the username upon failure.
21/*	The error result lives in static storage and must be saved
22/*	if it is to be used to across multiple check_user_acl_byuid()
23/*	calls.
24/*
25/*	Arguments:
26/* .IP pname
27/*	The parameter name of the acl.
28/* .IP acl
29/*	Authorized user name list suitable for input to string_list_init(3).
30/* .IP uid
31/*	The uid to be checked against the access list.
32/* LICENSE
33/* .ad
34/* .fi
35/*	The Secure Mailer license must be distributed with this software.
36/* AUTHOR(S)
37/*	Wietse Venema
38/*	IBM T.J. Watson Research
39/*	P.O. Box 704
40/*	Yorktown Heights, NY 10598, USA
41/*
42/*	Victor Duchovni
43/*	Morgan Stanley
44/*--*/
45
46/* System library. */
47
48#include <sys_defs.h>
49#include <string.h>
50
51/* Utility library. */
52
53#include <vstring.h>
54#include <dict_static.h>
55
56/* Global library. */
57
58#include <string_list.h>
59#include <mypwd.h>
60
61/* Application-specific. */
62
63#include "user_acl.h"
64
65/* check_user_acl_byuid - check user authorization */
66
67const char *check_user_acl_byuid(const char *pname, const char *acl, uid_t uid)
68{
69    struct mypasswd *mypwd;
70    STRING_LIST *list;
71    static VSTRING *who = 0;
72    int     matched;
73    const char *name;
74
75    /*
76     * Optimize for the most common case. This also makes Postfix a little
77     * more robust in the face of local infrastructure failures. Note that we
78     * only need to match the "static:" substring, not the result value.
79     */
80    if (strncmp(acl, DICT_TYPE_STATIC ":", sizeof(DICT_TYPE_STATIC)) == 0)
81	return (0);
82
83    /*
84     * XXX: Substitute "unknown" for UIDs without username, so that
85     * static:anyone results in "permit" even when the uid is not found in
86     * the password file, and so that a pattern of !unknown can be used to
87     * block non-existent accounts.
88     *
89     * The alternative is to use the UID as a surrogate lookup key for
90     * non-existent accounts. There are several reasons why this is not a
91     * good idea. 1) An ACL with a numerical UID should work regardless of
92     * whether or not an account has a password file entry. Therefore we
93     * would always have search on the numerical UID whenever the username
94     * fails to produce a match. 2) The string-list infrastructure is not
95     * really suitable for mixing numerical and non-numerical user
96     * information, because the numerical match is done in a separate pass
97     * from the non-numerical match. This breaks when the ! operator is used.
98     *
99     * XXX To avoid waiting until the lookup completes (e.g., LDAP or NIS down)
100     * invoke mypwuid_err(), and either change the user_acl() API to
101     * propagate the error to the caller, or treat lookup errors as fatal.
102     */
103    if ((mypwd = mypwuid(uid)) == 0) {
104	name = "unknown";
105    } else {
106	name = mypwd->pw_name;
107    }
108
109    list = string_list_init(pname, MATCH_FLAG_NONE, acl);
110    if ((matched = string_list_match(list, name)) == 0) {
111	if (!who)
112	    who = vstring_alloc(10);
113	vstring_strcpy(who, name);
114    }
115    string_list_free(list);
116    if (mypwd)
117	mypwfree(mypwd);
118
119    return (matched ? 0 : vstring_str(who));
120}
121