xref: /netbsd-src/external/ibm-public/postfix/dist/src/global/user_acl.c (revision e89934bbf778a6d6d6894877c4da59d0c7835b0f)
1*e89934bbSchristos /*	$NetBSD: user_acl.c,v 1.2 2017/02/14 01:16:45 christos Exp $	*/
241fbaed0Stron 
341fbaed0Stron /*++
441fbaed0Stron /* NAME
541fbaed0Stron /*	user_acl 3
641fbaed0Stron /* SUMMARY
741fbaed0Stron /*	user name based access control
841fbaed0Stron /* SYNOPSIS
941fbaed0Stron /*	#include <user_acl.h>
1041fbaed0Stron /*
11e262b48eSchristos /*	const char *check_user_acl_byuid(pname, acl, uid)
12e262b48eSchristos /*	const char *pname;
1341fbaed0Stron /*	const char *acl;
1441fbaed0Stron /*	uid_t	uid;
1541fbaed0Stron /* DESCRIPTION
1641fbaed0Stron /*	check_user_acl_byuid() converts the given uid into a user
1741fbaed0Stron /*	name, and checks the result against a user name matchlist.
1841fbaed0Stron /*	If the uid cannot be resolved to a user name, "unknown"
1941fbaed0Stron /*	is used as the lookup key instead.
2041fbaed0Stron /*	The result is NULL on success, the username upon failure.
2141fbaed0Stron /*	The error result lives in static storage and must be saved
2241fbaed0Stron /*	if it is to be used to across multiple check_user_acl_byuid()
2341fbaed0Stron /*	calls.
2441fbaed0Stron /*
2541fbaed0Stron /*	Arguments:
26e262b48eSchristos /* .IP pname
27e262b48eSchristos /*	The parameter name of the acl.
2841fbaed0Stron /* .IP acl
2941fbaed0Stron /*	Authorized user name list suitable for input to string_list_init(3).
3041fbaed0Stron /* .IP uid
3141fbaed0Stron /*	The uid to be checked against the access list.
3241fbaed0Stron /* LICENSE
3341fbaed0Stron /* .ad
3441fbaed0Stron /* .fi
3541fbaed0Stron /*	The Secure Mailer license must be distributed with this software.
3641fbaed0Stron /* AUTHOR(S)
3741fbaed0Stron /*	Wietse Venema
3841fbaed0Stron /*	IBM T.J. Watson Research
3941fbaed0Stron /*	P.O. Box 704
4041fbaed0Stron /*	Yorktown Heights, NY 10598, USA
4141fbaed0Stron /*
4241fbaed0Stron /*	Victor Duchovni
4341fbaed0Stron /*	Morgan Stanley
4441fbaed0Stron /*--*/
4541fbaed0Stron 
4641fbaed0Stron /* System library. */
4741fbaed0Stron 
4841fbaed0Stron #include <sys_defs.h>
4941fbaed0Stron #include <string.h>
5041fbaed0Stron 
5141fbaed0Stron /* Utility library. */
5241fbaed0Stron 
5341fbaed0Stron #include <vstring.h>
54a30b880eStron #include <dict_static.h>
5541fbaed0Stron 
5641fbaed0Stron /* Global library. */
5741fbaed0Stron 
5841fbaed0Stron #include <string_list.h>
5941fbaed0Stron #include <mypwd.h>
6041fbaed0Stron 
6141fbaed0Stron /* Application-specific. */
6241fbaed0Stron 
6341fbaed0Stron #include "user_acl.h"
6441fbaed0Stron 
6541fbaed0Stron /* check_user_acl_byuid - check user authorization */
6641fbaed0Stron 
check_user_acl_byuid(const char * pname,const char * acl,uid_t uid)67e262b48eSchristos const char *check_user_acl_byuid(const char *pname, const char *acl, uid_t uid)
6841fbaed0Stron {
6941fbaed0Stron     struct mypasswd *mypwd;
7041fbaed0Stron     STRING_LIST *list;
7141fbaed0Stron     static VSTRING *who = 0;
7241fbaed0Stron     int     matched;
7341fbaed0Stron     const char *name;
7441fbaed0Stron 
7541fbaed0Stron     /*
7641fbaed0Stron      * Optimize for the most common case. This also makes Postfix a little
77a30b880eStron      * more robust in the face of local infrastructure failures. Note that we
78a30b880eStron      * only need to match the "static:" substring, not the result value.
7941fbaed0Stron      */
80a30b880eStron     if (strncmp(acl, DICT_TYPE_STATIC ":", sizeof(DICT_TYPE_STATIC)) == 0)
8141fbaed0Stron 	return (0);
8241fbaed0Stron 
8341fbaed0Stron     /*
8441fbaed0Stron      * XXX: Substitute "unknown" for UIDs without username, so that
8541fbaed0Stron      * static:anyone results in "permit" even when the uid is not found in
8641fbaed0Stron      * the password file, and so that a pattern of !unknown can be used to
8741fbaed0Stron      * block non-existent accounts.
8841fbaed0Stron      *
8941fbaed0Stron      * The alternative is to use the UID as a surrogate lookup key for
9041fbaed0Stron      * non-existent accounts. There are several reasons why this is not a
9141fbaed0Stron      * good idea. 1) An ACL with a numerical UID should work regardless of
9241fbaed0Stron      * whether or not an account has a password file entry. Therefore we
9341fbaed0Stron      * would always have search on the numerical UID whenever the username
9441fbaed0Stron      * fails to produce a match. 2) The string-list infrastructure is not
9541fbaed0Stron      * really suitable for mixing numerical and non-numerical user
9641fbaed0Stron      * information, because the numerical match is done in a separate pass
9741fbaed0Stron      * from the non-numerical match. This breaks when the ! operator is used.
98a30b880eStron      *
99a30b880eStron      * XXX To avoid waiting until the lookup completes (e.g., LDAP or NIS down)
100a30b880eStron      * invoke mypwuid_err(), and either change the user_acl() API to
101a30b880eStron      * propagate the error to the caller, or treat lookup errors as fatal.
10241fbaed0Stron      */
10341fbaed0Stron     if ((mypwd = mypwuid(uid)) == 0) {
10441fbaed0Stron 	name = "unknown";
10541fbaed0Stron     } else {
10641fbaed0Stron 	name = mypwd->pw_name;
10741fbaed0Stron     }
10841fbaed0Stron 
109e262b48eSchristos     list = string_list_init(pname, MATCH_FLAG_NONE, acl);
11041fbaed0Stron     if ((matched = string_list_match(list, name)) == 0) {
11141fbaed0Stron 	if (!who)
11241fbaed0Stron 	    who = vstring_alloc(10);
11341fbaed0Stron 	vstring_strcpy(who, name);
11441fbaed0Stron     }
11541fbaed0Stron     string_list_free(list);
11641fbaed0Stron     if (mypwd)
11741fbaed0Stron 	mypwfree(mypwd);
11841fbaed0Stron 
11941fbaed0Stron     return (matched ? 0 : vstring_str(who));
12041fbaed0Stron }
121