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