Home | History | Annotate | Line # | Download | only in global
      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 
     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