summaryrefslogtreecommitdiff
path: root/nss_mapuid.c
blob: acee3f539aee7467454e319677b722a92bcf764c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/*
 * Copyright (C) 2017 Cumulus Networks, Inc.
 * All rights reserved.
 * Author: Dave Olson <olson@cumulusnetworks.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program - see the file COPYING.
 */

/*
 * This plugin implements getpwuid_r for NSS to map a UID back to
 * a mapped username account, set up via nss_mapuser.
 *
 * A fixed account is used to get the base of the home directory,
 * and for the uid and gid.  All other fields are replaced, and
 * the password is always returned as 'x' (disabled).  The assumption
 * is that any authentication and authorization will be done via PAM
 * using some mechanism other than the local password file.
 *
 * Since this should match first whenever a mapped user's UID is being
 * looked up, this module should appear first in in nsswitch.conf for
 * the passwd database.
 *
 * It implements getpwuid_r for UIDs if and only if a mapped user is currently
 * logged in This means that if you do, e.g.:
 *     ls -ld ~SomeUserName
 * you will sometimes get a mapped username, and other times get the name of the
 * fixed account in the configuration file, depending on whether a mapped user
 * is logged in or not.
 *
 * See nss_mapuser.c for the matching getpwnam_r for UIDs.
 */

#include "map_common.h"
#include <sys/types.h>

static const char *nssname = "nss_mapuid";	/* for syslogs */

/*
 * This is an NSS entry point.
 * We implement getpwuid(), for anything that wants to get the original
 * login name from the uid.
 * If it matches an entry in the map, we use that data to replace
 * the data from the local passwd file (not via NSS).
 * locally from the map.
 *
 * This can be made to work 2 different ways, and we need to choose
 * one, or make it configurable.
 *
 * 1) Given a valid session id, and a mapped user logged in,
 * we'll match only that user.   That is, we can only do the lookup
 * successfully for child processes of the mapped login, and
 * only while still logged in (map entry is valid).
 *
 * For now, if session are set, I try them, and if that lookup
 * fails, try the wildcard.
 *
 * Only works while the UID is in use for a mapped user, and only
 * for processes invoked from that session.  Other callers will
 * just get the files, ldap, etc. entry for the UID
 * Returns the first match if multiple mapped users.
 */
__attribute__ ((visibility("default")))
enum nss_status _nss_mapuid_getpwuid_r(uid_t uid, struct passwd *pw,
				       char *buffer, size_t buflen, int *errnop)
{
	struct pwbuf pb;
	enum nss_status status = NSS_STATUS_NOTFOUND;
	uint32_t session;

	if (map_init_common(errnop, nssname))
		return status;

	if (map_min_uid != ~0U && uid < map_min_uid) {
		if (map_debug > 1)
			syslog(LOG_DEBUG,
			       "%s: uid %u < map_min_uid %u, don't lookup",
			       nssname, uid, map_min_uid);
		return status;
	}

	/* marshal the args for the lower level functions */
	pb.pw = pw;
	pb.buf = buffer;
	pb.buflen = buflen;
	pb.errnop = errnop;
	pb.name = NULL;

	/* session needs to be set to lookup this user.  May also be set
	 * for other users.
	 */
	session = get_sessionid();
	if (session && !find_mapped_name(&pb, uid, session))
		status = NSS_STATUS_SUCCESS;
	if (status != NSS_STATUS_SUCCESS) {
		/* lookup by some other user or unrelated process, try dir lookup */
		if (!find_mappingfile(&pb, uid))
			status = NSS_STATUS_SUCCESS;
	}
	return status;
}