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
check_user_acl_byuid(const char * pname,const char * acl,uid_t uid)67 const 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