Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F142738323
D23198.id67499.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
15 KB
Referenced Files
None
Subscribers
None
D23198.id67499.diff
View Options
Index: lib/libpam/modules/pam_login_access/login.access.5
===================================================================
--- lib/libpam/modules/pam_login_access/login.access.5
+++ lib/libpam/modules/pam_login_access/login.access.5
@@ -1,12 +1,14 @@
.\"
.\" $FreeBSD$
.\"
-.Dd May 7, 2019
+.Dd January 30, 2020
.Dt LOGIN.ACCESS 5
.Os
.Sh NAME
.Nm login.access
.Nd login access control table
+.Sh SYNOPSIS
+.Pa /etc/login.access
.Sh DESCRIPTION
The
.Nm
@@ -32,6 +34,13 @@
.Pp
The second field should be a list of one or more login names,
group names, or ALL (always matches).
+Group names must be enclosed in
+parentheses if the pam module specification for
+.Pa pam_login_access
+specifies the
+.Pa nodefgroup
+option.
+Otherwise group names will only match if no usernames match.
.Pp
The third field should be a list
of one or more tty names (for non-networked logins), host names, domain
Index: lib/libpam/modules/pam_login_access/login_access.c
===================================================================
--- lib/libpam/modules/pam_login_access/login_access.c
+++ lib/libpam/modules/pam_login_access/login_access.c
@@ -17,10 +17,12 @@
__FBSDID("$FreeBSD$");
#include <sys/types.h>
+#include <sys/param.h>
#include <ctype.h>
#include <errno.h>
#include <grp.h>
#include <netdb.h>
+#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -29,29 +31,25 @@
#include "pam_login_access.h"
-#define _PATH_LOGACCESS "/etc/login.access"
-
- /* Delimiters for fields and for lists of users, ttys or hosts. */
-
-static char fs[] = ":"; /* field separator */
-static char sep[] = ", \t"; /* list-element separator */
-
/* Constants to be used in assignments only, not in comparisons... */
#define YES 1
#define NO 0
-static int from_match(const char *, const char *);
+static int from_match(const char *, const char *, struct pam_login_access_options *);
static int list_match(char *, const char *,
- int (*)(const char *, const char *));
+ int (*)(const char *, const char *,
+ struct pam_login_access_options *),
+ struct pam_login_access_options *);
static int netgroup_match(const char *, const char *, const char *);
static int string_match(const char *, const char *);
-static int user_match(const char *, const char *);
+static int user_match(const char *, const char *, struct pam_login_access_options *);
+static int group_match(const char *, const char *);
/* login_access - match username/group and host/tty with access control file */
int
-login_access(const char *user, const char *from)
+login_access(const char *user, const char *from, struct pam_login_access_options *login_access_opts)
{
FILE *fp;
char line[BUFSIZ];
@@ -61,6 +59,7 @@
int match = NO;
int end;
int lineno = 0; /* for diagnostics */
+ const char *fieldsep = login_access_opts->fieldsep;
/*
* Process the table one line at a time and stop at the first match.
@@ -70,12 +69,12 @@
* non-existing table means no access control.
*/
- if ((fp = fopen(_PATH_LOGACCESS, "r")) != NULL) {
+ if ((fp = fopen(login_access_opts->accessfile, "r")) != NULL) {
while (!match && fgets(line, sizeof(line), fp)) {
lineno++;
if (line[end = strlen(line) - 1] != '\n') {
syslog(LOG_ERR, "%s: line %d: missing newline or line too long",
- _PATH_LOGACCESS, lineno);
+ login_access_opts->accessfile, lineno);
continue;
}
if (line[0] == '#')
@@ -85,25 +84,25 @@
line[end] = 0; /* strip trailing whitespace */
if (line[0] == 0) /* skip blank lines */
continue;
- if (!(perm = strtok(line, fs))
- || !(users = strtok((char *) 0, fs))
- || !(froms = strtok((char *) 0, fs))
- || strtok((char *) 0, fs)) {
- syslog(LOG_ERR, "%s: line %d: bad field count", _PATH_LOGACCESS,
+ if (!(perm = strtok(line, fieldsep))
+ || !(users = strtok((char *) 0, fieldsep))
+ || !(froms = strtok((char *) 0, fieldsep))
+ || strtok((char *) 0, fieldsep)) {
+ syslog(LOG_ERR, "%s: line %d: bad field count", login_access_opts->accessfile,
lineno);
continue;
}
if (perm[0] != '+' && perm[0] != '-') {
- syslog(LOG_ERR, "%s: line %d: bad first field", _PATH_LOGACCESS,
+ syslog(LOG_ERR, "%s: line %d: bad first field", login_access_opts->accessfile,
lineno);
continue;
}
- match = (list_match(froms, from, from_match)
- && list_match(users, user, user_match));
+ match = (list_match(froms, from, from_match, login_access_opts)
+ && list_match(users, user, user_match, login_access_opts));
}
(void) fclose(fp);
} else if (errno != ENOENT) {
- syslog(LOG_ERR, "cannot open %s: %m", _PATH_LOGACCESS);
+ syslog(LOG_ERR, "cannot open %s: %m", login_access_opts->accessfile);
}
return (match == 0 || (line[0] == '+'));
}
@@ -112,10 +111,12 @@
static int
list_match(char *list, const char *item,
- int (*match_fn)(const char *, const char *))
+ int (*match_fn)(const char *, const char *, struct pam_login_access_options *),
+ struct pam_login_access_options *login_access_opts)
{
char *tok;
int match = NO;
+ const char *listsep = login_access_opts->listsep;
/*
* Process tokens one at a time. We have exhausted all possible matches
@@ -124,19 +125,20 @@
* the match is affected by any exceptions.
*/
- for (tok = strtok(list, sep); tok != NULL; tok = strtok((char *) 0, sep)) {
- if (strcasecmp(tok, "EXCEPT") == 0) /* EXCEPT: give up */
+ for (tok = strtok(list, listsep); tok != NULL; tok = strtok((char *) 0, listsep)) {
+ if (strcmp(tok, "EXCEPT") == 0) /* EXCEPT: give up */
break;
- if ((match = (*match_fn)(tok, item)) != 0) /* YES */
+ if ((match = (*match_fn)(tok, item, login_access_opts)) != 0) /* YES */
break;
}
/* Process exceptions to matches. */
if (match != NO) {
- while ((tok = strtok((char *) 0, sep)) && strcasecmp(tok, "EXCEPT"))
+ while ((tok = strtok((char *) 0, listsep)) && strcmp(tok, "EXCEPT"))
/* VOID */ ;
- if (tok == NULL || list_match((char *) 0, item, match_fn) == NO)
- return (match);
+ if (tok == NULL || list_match((char *) 0, item, match_fn,
+ login_access_opts) == NO)
+ return (match);
}
return (NO);
}
@@ -168,13 +170,49 @@
return (NO);
}
+/* group_match - match a group against one token */
+
+int
+group_match(const char *tok, const char *groupname)
+{
+ struct group *group;
+ struct passwd *passwd;
+ gid_t *grouplist;
+ int i, ret, ngroups = NGROUPS;
+
+ if ((passwd = getpwnam(groupname)) == NULL)
+ return (NO);
+ errno = 0;
+ if ((group = getgrnam(tok)) == NULL) {
+ if (errno != 0)
+ syslog(LOG_ERR, "getgrnam() failed for %s: %s", groupname, strerror(errno));
+ else
+ syslog(LOG_NOTICE, "group not found: %s", groupname);
+ return (NO);
+ }
+ if ((grouplist = calloc(ngroups, sizeof(gid_t))) == NULL) {
+ syslog(LOG_ERR, "cannot allocate memory for grouplist: %s", groupname);
+ return (NO);
+ }
+ ret = NO;
+ if (getgrouplist(groupname, passwd->pw_gid, grouplist, &ngroups) != 0)
+ syslog(LOG_ERR, "getgrouplist() failed for %s", groupname);
+ for (i = 0; i < ngroups; i++)
+ if (grouplist[i] == group->gr_gid)
+ ret = YES;
+ free(grouplist);
+ return (ret);
+}
+
/* user_match - match a username against one token */
static int
-user_match(const char *tok, const char *string)
+user_match(const char *tok, const char *string,
+ struct pam_login_access_options *login_access_opts)
{
- struct group *group;
- int i;
+ size_t stringlen;
+ char *grpstr;
+ int rc;
/*
* If a token has the magic value "ALL" the match always succeeds.
@@ -184,12 +222,18 @@
if (tok[0] == '@') { /* netgroup */
return (netgroup_match(tok + 1, (char *) 0, string));
+ } else if (tok[0] == '(' && tok[(stringlen = strlen(&tok[1]))] == ')') { /* group */
+ if ((grpstr = strndup(&tok[1], stringlen - 1)) == NULL) {
+ syslog(LOG_ERR, "cannot allocate memory for %s", string);
+ return (NO);
+ }
+ rc = group_match(grpstr, string);
+ free(grpstr);
+ return (rc);
} else if (string_match(tok, string)) { /* ALL or exact match */
return (YES);
- } else if ((group = getgrnam(tok)) != NULL) {/* try group membership */
- for (i = 0; group->gr_mem[i]; i++)
- if (strcasecmp(string, group->gr_mem[i]) == 0)
- return (YES);
+ } else if (login_access_opts->defgroup == true) {/* try group membership */
+ return (group_match(tok, string) == YES);
}
return (NO);
}
@@ -197,7 +241,8 @@
/* from_match - match a host or tty against a list of tokens */
static int
-from_match(const char *tok, const char *string)
+from_match(const char *tok, const char *string,
+ struct pam_login_access_options *login_access_opts __unused)
{
int tok_len;
int str_len;
@@ -219,8 +264,8 @@
if ((str_len = strlen(string)) > (tok_len = strlen(tok))
&& strcasecmp(tok, string + str_len - tok_len) == 0)
return (YES);
- } else if (strcasecmp(tok, "LOCAL") == 0) { /* local: no dots */
- if (strchr(string, '.') == 0)
+ } else if (strcmp(tok, "LOCAL") == 0) { /* local: no dots */
+ if (strchr(string, '.') == NULL)
return (YES);
} else if (tok[(tok_len = strlen(tok)) - 1] == '.' /* network */
&& strncmp(tok, string, tok_len) == 0) {
@@ -240,7 +285,7 @@
* Otherwise, return YES if the token fully matches the string.
*/
- if (strcasecmp(tok, "ALL") == 0) { /* all: always matches */
+ if (strcmp(tok, "ALL") == 0) { /* all: always matches */
return (YES);
} else if (strcasecmp(tok, string) == 0) { /* try exact match */
return (YES);
Index: lib/libpam/modules/pam_login_access/pam_login_access.h
===================================================================
--- lib/libpam/modules/pam_login_access/pam_login_access.h
+++ lib/libpam/modules/pam_login_access/pam_login_access.h
@@ -38,4 +38,15 @@
* $FreeBSD$
*/
-extern int login_access(const char *, const char *);
+#include <stdbool.h>
+
+struct pam_login_access_options {
+ bool defgroup;
+ bool audit;
+ const char *accessfile;
+ /* Delimiters for fields and for lists of users, ttys or hosts. */
+ const char *fieldsep; /* field separator */
+ const char *listsep; /* list-element separator */
+};
+
+extern int login_access(const char *, const char *, struct pam_login_access_options *);
Index: lib/libpam/modules/pam_login_access/pam_login_access.8
===================================================================
--- lib/libpam/modules/pam_login_access/pam_login_access.8
+++ lib/libpam/modules/pam_login_access/pam_login_access.8
@@ -34,7 +34,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd January 24, 2002
+.Dd January 30, 2020
.Dt PAM_LOGIN_ACCESS 8
.Os
.Sh NAME
@@ -63,15 +63,48 @@
.Pa login.access
account management component
.Pq Fn pam_sm_acct_mgmt ,
-returns success if and only the user is allowed to log in on the
+returns success if and only the user is allowed to login on the
specified tty (in the case of a local login) or from the specified
remote host (in the case of a remote login), according to the
restrictions listed in
.Xr login.access 5 .
+.Bl -tag -width ".Cm nodefgroup"
+.It Cm accessfile Ns = Ns Ar pathname
+specifies a non-standard location for the
+.Pa login.access
+configuration file
+(normally located in
+.Pa /etc/login.access ) .
+.It Cm nodefgroup
+makes tokens not enclosed in parentheses only match users, requiring groups
+to be specified in parentheses.
+Without
+.Cm nodefgroup
+user and group names are intermingled, with user entries taking precedence
+over group entries.
+This is not backwards compatible with legacy
+.Pa login.access
+configuration files.
+However this mitigates confusion between users and
+groups of the same name.
+.It Cm fieldsep Ns = Ns Ar separators
+changes the field separator from the default ":".
+More than one separator
+may be specified.
+.It Cm listsep Ns = Ns Ar separators
+changes the field separator from the default space (''), tab (\\t) and
+comma (,).
+More than one separator may be specified.
+For example, listsep=;
+will replace the default with a semicolon (;).
+This option may be useful when specifying Active Directory groupnames which
+typically contain spaces.
+.El
.Sh SEE ALSO
+.Xr pam 3 ,
+.Xr syslog 3 ,
.Xr login.access 5 ,
-.Xr pam.conf 5 ,
-.Xr pam 8
+.Xr pam.conf 5
.Sh AUTHORS
The
.Xr login.access 5
Index: lib/libpam/modules/pam_login_access/pam_login_access.c
===================================================================
--- lib/libpam/modules/pam_login_access/pam_login_access.c
+++ lib/libpam/modules/pam_login_access/pam_login_access.c
@@ -42,6 +42,7 @@
#define _BSD_SOURCE
#include <sys/param.h>
+#include <sys/types.h>
#include <syslog.h>
#include <unistd.h>
@@ -51,13 +52,25 @@
#include <security/pam_appl.h>
#include <security/pam_modules.h>
#include <security/pam_mod_misc.h>
+#include <security/openpam.h>
#include "pam_login_access.h"
+#define OPT_ACCESSFILE "accessfile"
+#define OPT_NOAUDIT "noaudit"
+#define OPT_FIELDSEP "fieldsep"
+#define OPT_LISTSEP "listsep"
+#define OPT_NODEFGROUP "nodefgroup"
+
+#define _PATH_LOGACCESS "/etc/login.access"
+#define _FIELD_SEPARATOR ":"
+#define _LIST_SEPARATOR ", \t"
+
PAM_EXTERN int
pam_sm_acct_mgmt(pam_handle_t *pamh, int flags __unused,
int argc __unused, const char *argv[] __unused)
{
+ struct pam_login_access_options login_access_opts;
const void *rhost, *tty, *user;
char hostname[MAXHOSTNAMELEN];
int pam_err;
@@ -80,25 +93,33 @@
return (pam_err);
gethostname(hostname, sizeof hostname);
+ login_access_opts.defgroup = openpam_get_option(pamh, OPT_NODEFGROUP) == NULL ? true : false;
+ login_access_opts.audit = openpam_get_option(pamh, OPT_NOAUDIT) == NULL ? true : false;
+ if ((login_access_opts.accessfile = openpam_get_option(pamh, OPT_ACCESSFILE)) == NULL)
+ login_access_opts.accessfile = _PATH_LOGACCESS;
+ if ((login_access_opts.fieldsep = openpam_get_option(pamh, OPT_FIELDSEP)) == NULL)
+ login_access_opts.fieldsep = _FIELD_SEPARATOR;
+ if ((login_access_opts.listsep = openpam_get_option(pamh, OPT_LISTSEP)) == NULL)
+ login_access_opts.listsep = _LIST_SEPARATOR;
if (rhost != NULL && *(const char *)rhost != '\0') {
PAM_LOG("Checking login.access for user %s from host %s",
(const char *)user, (const char *)rhost);
- if (login_access(user, rhost) != 0)
+ if (login_access(user, rhost, &login_access_opts) != 0)
return (PAM_SUCCESS);
PAM_VERBOSE_ERROR("%s is not allowed to log in from %s",
(const char *)user, (const char *)rhost);
} else if (tty != NULL && *(const char *)tty != '\0') {
PAM_LOG("Checking login.access for user %s on tty %s",
(const char *)user, (const char *)tty);
- if (login_access(user, tty) != 0)
+ if (login_access(user, tty, &login_access_opts) != 0)
return (PAM_SUCCESS);
PAM_VERBOSE_ERROR("%s is not allowed to log in on %s",
(const char *)user, (const char *)tty);
} else {
PAM_LOG("Checking login.access for user %s",
(const char *)user);
- if (login_access(user, "***unknown***") != 0)
+ if (login_access(user, "***unknown***", &login_access_opts) != 0)
return (PAM_SUCCESS);
PAM_VERBOSE_ERROR("%s is not allowed to log in",
(const char *)user);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Jan 23, 10:39 PM (13 h, 15 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27890264
Default Alt Text
D23198.id67499.diff (15 KB)
Attached To
Mode
D23198: Bring our pam_login_access to support the same features as Linux's pam_access
Attached
Detach File
Event Timeline
Log In to Comment