xref: /onnv-gate/usr/src/lib/nsswitch/ad/common/getpwnam.c (revision 8040:42abce45ef67)
1*8040SBaban.Kenkre@Sun.COM /*
2*8040SBaban.Kenkre@Sun.COM  * CDDL HEADER START
3*8040SBaban.Kenkre@Sun.COM  *
4*8040SBaban.Kenkre@Sun.COM  * The contents of this file are subject to the terms of the
5*8040SBaban.Kenkre@Sun.COM  * Common Development and Distribution License (the "License").
6*8040SBaban.Kenkre@Sun.COM  * You may not use this file except in compliance with the License.
7*8040SBaban.Kenkre@Sun.COM  *
8*8040SBaban.Kenkre@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*8040SBaban.Kenkre@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*8040SBaban.Kenkre@Sun.COM  * See the License for the specific language governing permissions
11*8040SBaban.Kenkre@Sun.COM  * and limitations under the License.
12*8040SBaban.Kenkre@Sun.COM  *
13*8040SBaban.Kenkre@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*8040SBaban.Kenkre@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*8040SBaban.Kenkre@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*8040SBaban.Kenkre@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*8040SBaban.Kenkre@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*8040SBaban.Kenkre@Sun.COM  *
19*8040SBaban.Kenkre@Sun.COM  * CDDL HEADER END
20*8040SBaban.Kenkre@Sun.COM  */
21*8040SBaban.Kenkre@Sun.COM /*
22*8040SBaban.Kenkre@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*8040SBaban.Kenkre@Sun.COM  * Use is subject to license terms.
24*8040SBaban.Kenkre@Sun.COM  */
25*8040SBaban.Kenkre@Sun.COM 
26*8040SBaban.Kenkre@Sun.COM #include <pwd.h>
27*8040SBaban.Kenkre@Sun.COM #include <idmap.h>
28*8040SBaban.Kenkre@Sun.COM #include <ctype.h>
29*8040SBaban.Kenkre@Sun.COM #include "ad_common.h"
30*8040SBaban.Kenkre@Sun.COM 
31*8040SBaban.Kenkre@Sun.COM /* passwd attributes and filters */
32*8040SBaban.Kenkre@Sun.COM #define	_PWD_DN			"dn"
33*8040SBaban.Kenkre@Sun.COM #define	_PWD_SAN		"sAMAccountName"
34*8040SBaban.Kenkre@Sun.COM #define	_PWD_OBJSID		"objectSid"
35*8040SBaban.Kenkre@Sun.COM #define	_PWD_PRIMARYGROUPID	"primaryGroupID"
36*8040SBaban.Kenkre@Sun.COM #define	_PWD_CN			"cn"
37*8040SBaban.Kenkre@Sun.COM #define	_PWD_HOMEDIRECTORY	"homedirectory"
38*8040SBaban.Kenkre@Sun.COM #define	_PWD_LOGINSHELL		"loginshell"
39*8040SBaban.Kenkre@Sun.COM #define	_PWD_OBJCLASS		"objectClass"
40*8040SBaban.Kenkre@Sun.COM 
41*8040SBaban.Kenkre@Sun.COM #define	_F_GETPWNAM		"(sAMAccountName=%.*s)"
42*8040SBaban.Kenkre@Sun.COM #define	_F_GETPWUID		"(objectSid=%s)"
43*8040SBaban.Kenkre@Sun.COM 
44*8040SBaban.Kenkre@Sun.COM static const char *pwd_attrs[] = {
45*8040SBaban.Kenkre@Sun.COM 	_PWD_SAN,
46*8040SBaban.Kenkre@Sun.COM 	_PWD_OBJSID,
47*8040SBaban.Kenkre@Sun.COM 	_PWD_PRIMARYGROUPID,
48*8040SBaban.Kenkre@Sun.COM 	_PWD_CN,
49*8040SBaban.Kenkre@Sun.COM 	_PWD_HOMEDIRECTORY,
50*8040SBaban.Kenkre@Sun.COM 	_PWD_LOGINSHELL,
51*8040SBaban.Kenkre@Sun.COM 	_PWD_OBJCLASS,
52*8040SBaban.Kenkre@Sun.COM 	(char *)NULL
53*8040SBaban.Kenkre@Sun.COM };
54*8040SBaban.Kenkre@Sun.COM 
55*8040SBaban.Kenkre@Sun.COM static int
56*8040SBaban.Kenkre@Sun.COM update_buffer(ad_backend_ptr be, nss_XbyY_args_t *argp,
57*8040SBaban.Kenkre@Sun.COM 		const char *name, const char *domain,
58*8040SBaban.Kenkre@Sun.COM 		uid_t uid, gid_t gid, const char *gecos,
59*8040SBaban.Kenkre@Sun.COM 		const char *homedir, const char *shell)
60*8040SBaban.Kenkre@Sun.COM {
61*8040SBaban.Kenkre@Sun.COM 	int	buflen;
62*8040SBaban.Kenkre@Sun.COM 	char	*buffer;
63*8040SBaban.Kenkre@Sun.COM 
64*8040SBaban.Kenkre@Sun.COM 	if (be->db_type == NSS_AD_DB_PASSWD_BYNAME) {
65*8040SBaban.Kenkre@Sun.COM 		/*
66*8040SBaban.Kenkre@Sun.COM 		 * The canonical name obtained from AD lookup may not match
67*8040SBaban.Kenkre@Sun.COM 		 * the case of the name (i.e. key) in the request. Therefore,
68*8040SBaban.Kenkre@Sun.COM 		 * use the name from the request to construct the result.
69*8040SBaban.Kenkre@Sun.COM 		 */
70*8040SBaban.Kenkre@Sun.COM 		buflen = snprintf(NULL, 0, "%s:%s:%u:%u:%s:%s:%s",
71*8040SBaban.Kenkre@Sun.COM 		    argp->key.name, "x", uid, gid, gecos, homedir, shell) + 1;
72*8040SBaban.Kenkre@Sun.COM 	} else {
73*8040SBaban.Kenkre@Sun.COM 		if (domain == NULL)
74*8040SBaban.Kenkre@Sun.COM 			domain = WK_DOMAIN;
75*8040SBaban.Kenkre@Sun.COM 		buflen = snprintf(NULL, 0, "%s@%s:%s:%u:%u:%s:%s:%s",
76*8040SBaban.Kenkre@Sun.COM 		    name, domain, "x", uid, gid, gecos, homedir, shell) + 1;
77*8040SBaban.Kenkre@Sun.COM 	}
78*8040SBaban.Kenkre@Sun.COM 
79*8040SBaban.Kenkre@Sun.COM 
80*8040SBaban.Kenkre@Sun.COM 	if (argp->buf.result != NULL) {
81*8040SBaban.Kenkre@Sun.COM 		buffer = be->buffer = malloc(buflen);
82*8040SBaban.Kenkre@Sun.COM 		if (be->buffer == NULL)
83*8040SBaban.Kenkre@Sun.COM 			return (-1);
84*8040SBaban.Kenkre@Sun.COM 		be->buflen = buflen;
85*8040SBaban.Kenkre@Sun.COM 	} else {
86*8040SBaban.Kenkre@Sun.COM 		if (buflen > argp->buf.buflen)
87*8040SBaban.Kenkre@Sun.COM 			return (-1);
88*8040SBaban.Kenkre@Sun.COM 		buflen = argp->buf.buflen;
89*8040SBaban.Kenkre@Sun.COM 		buffer = argp->buf.buffer;
90*8040SBaban.Kenkre@Sun.COM 	}
91*8040SBaban.Kenkre@Sun.COM 
92*8040SBaban.Kenkre@Sun.COM 	if (be->db_type == NSS_AD_DB_PASSWD_BYNAME)
93*8040SBaban.Kenkre@Sun.COM 		(void) snprintf(buffer, buflen, "%s:%s:%u:%u:%s:%s:%s",
94*8040SBaban.Kenkre@Sun.COM 		    argp->key.name, "x", uid, gid, gecos, homedir, shell);
95*8040SBaban.Kenkre@Sun.COM 	else
96*8040SBaban.Kenkre@Sun.COM 		(void) snprintf(buffer, buflen, "%s@%s:%s:%u:%u:%s:%s:%s",
97*8040SBaban.Kenkre@Sun.COM 		    name, domain, "x", uid, gid, gecos, homedir, shell);
98*8040SBaban.Kenkre@Sun.COM 	return (0);
99*8040SBaban.Kenkre@Sun.COM }
100*8040SBaban.Kenkre@Sun.COM 
101*8040SBaban.Kenkre@Sun.COM 
102*8040SBaban.Kenkre@Sun.COM #define	NET_SCHEME	"/net"
103*8040SBaban.Kenkre@Sun.COM 
104*8040SBaban.Kenkre@Sun.COM /*
105*8040SBaban.Kenkre@Sun.COM  * 1) If the homeDirectory string is in UNC format then convert it into
106*8040SBaban.Kenkre@Sun.COM  * a /net format. This needs to be revisited later but is fine for now
107*8040SBaban.Kenkre@Sun.COM  * because Solaris does not support -hosts automount map for CIFS yet.
108*8040SBaban.Kenkre@Sun.COM  *
109*8040SBaban.Kenkre@Sun.COM  * 2) If homeDirectory contains ':' then return NULL because ':' is the
110*8040SBaban.Kenkre@Sun.COM  * delimiter in passwd entries and may break apps that parse these entries.
111*8040SBaban.Kenkre@Sun.COM  *
112*8040SBaban.Kenkre@Sun.COM  * 3) For all other cases return the same string that was passed to
113*8040SBaban.Kenkre@Sun.COM  * this function.
114*8040SBaban.Kenkre@Sun.COM  */
115*8040SBaban.Kenkre@Sun.COM static
116*8040SBaban.Kenkre@Sun.COM char *
117*8040SBaban.Kenkre@Sun.COM process_homedir(char *homedir)
118*8040SBaban.Kenkre@Sun.COM {
119*8040SBaban.Kenkre@Sun.COM 	size_t	len, smb_len;
120*8040SBaban.Kenkre@Sun.COM 	char	*smb_homedir;
121*8040SBaban.Kenkre@Sun.COM 	int	i, slash = 0;
122*8040SBaban.Kenkre@Sun.COM 
123*8040SBaban.Kenkre@Sun.COM 	len = strlen(homedir);
124*8040SBaban.Kenkre@Sun.COM 
125*8040SBaban.Kenkre@Sun.COM 	if (strchr(homedir, ':') != NULL)
126*8040SBaban.Kenkre@Sun.COM 		/*
127*8040SBaban.Kenkre@Sun.COM 		 * Ignore paths that have colon ':' because ':' is a
128*8040SBaban.Kenkre@Sun.COM 		 * delimiter for the passwd entry.
129*8040SBaban.Kenkre@Sun.COM 		 */
130*8040SBaban.Kenkre@Sun.COM 		return (NULL);
131*8040SBaban.Kenkre@Sun.COM 
132*8040SBaban.Kenkre@Sun.COM 	if (!(len > 1 && homedir[0] == '\\' && homedir[1] == '\\'))
133*8040SBaban.Kenkre@Sun.COM 		/* Keep homedir intact if not in UNC format */
134*8040SBaban.Kenkre@Sun.COM 		return (homedir);
135*8040SBaban.Kenkre@Sun.COM 
136*8040SBaban.Kenkre@Sun.COM 	/*
137*8040SBaban.Kenkre@Sun.COM 	 * Convert UNC string into /net format
138*8040SBaban.Kenkre@Sun.COM 	 * Example: \\server\abc -> /net/server/abc
139*8040SBaban.Kenkre@Sun.COM 	 */
140*8040SBaban.Kenkre@Sun.COM 	smb_len = len + 1 + sizeof (NET_SCHEME);
141*8040SBaban.Kenkre@Sun.COM 	if ((smb_homedir = calloc(1, smb_len)) == NULL)
142*8040SBaban.Kenkre@Sun.COM 		return (NULL);
143*8040SBaban.Kenkre@Sun.COM 	(void) strlcpy(smb_homedir, NET_SCHEME, smb_len);
144*8040SBaban.Kenkre@Sun.COM 	for (i = strlen(smb_homedir); *homedir != '\0'; homedir++) {
145*8040SBaban.Kenkre@Sun.COM 		if (*homedir == '\\') {
146*8040SBaban.Kenkre@Sun.COM 			/* Reduce double backslashes into one */
147*8040SBaban.Kenkre@Sun.COM 			if (slash)
148*8040SBaban.Kenkre@Sun.COM 				slash = 0;
149*8040SBaban.Kenkre@Sun.COM 			else {
150*8040SBaban.Kenkre@Sun.COM 				slash = 1;
151*8040SBaban.Kenkre@Sun.COM 				smb_homedir[i++] = '/';
152*8040SBaban.Kenkre@Sun.COM 			}
153*8040SBaban.Kenkre@Sun.COM 		} else {
154*8040SBaban.Kenkre@Sun.COM 			smb_homedir[i++] = *homedir;
155*8040SBaban.Kenkre@Sun.COM 			slash = 0;
156*8040SBaban.Kenkre@Sun.COM 		}
157*8040SBaban.Kenkre@Sun.COM 	}
158*8040SBaban.Kenkre@Sun.COM 	return (smb_homedir);
159*8040SBaban.Kenkre@Sun.COM }
160*8040SBaban.Kenkre@Sun.COM 
161*8040SBaban.Kenkre@Sun.COM /*
162*8040SBaban.Kenkre@Sun.COM  * _nss_ad_passwd2str is the data marshaling method for the passwd getXbyY
163*8040SBaban.Kenkre@Sun.COM  * (e.g., getbyuid(), getbyname(), getpwent()) backend processes. This method is
164*8040SBaban.Kenkre@Sun.COM  * called after a successful AD search has been performed. This method will
165*8040SBaban.Kenkre@Sun.COM  * parse the AD search values into the file format.
166*8040SBaban.Kenkre@Sun.COM  * e.g.
167*8040SBaban.Kenkre@Sun.COM  *
168*8040SBaban.Kenkre@Sun.COM  * blue@whale:x:123456:10:Blue Whale:/:
169*8040SBaban.Kenkre@Sun.COM  *
170*8040SBaban.Kenkre@Sun.COM  */
171*8040SBaban.Kenkre@Sun.COM static int
172*8040SBaban.Kenkre@Sun.COM _nss_ad_passwd2str(ad_backend_ptr be, nss_XbyY_args_t *argp)
173*8040SBaban.Kenkre@Sun.COM {
174*8040SBaban.Kenkre@Sun.COM 	int			nss_result;
175*8040SBaban.Kenkre@Sun.COM 	adutils_result_t	*result = be->result;
176*8040SBaban.Kenkre@Sun.COM 	const adutils_entry_t	*entry;
177*8040SBaban.Kenkre@Sun.COM 	char			**sid_v, *ptr, **pgid_v, *end;
178*8040SBaban.Kenkre@Sun.COM 	ulong_t			tmp;
179*8040SBaban.Kenkre@Sun.COM 	uint32_t		urid, grid;
180*8040SBaban.Kenkre@Sun.COM 	uid_t			uid;
181*8040SBaban.Kenkre@Sun.COM 	gid_t			gid;
182*8040SBaban.Kenkre@Sun.COM 	idmap_stat		gstat;
183*8040SBaban.Kenkre@Sun.COM 	idmap_get_handle_t 	*ig = NULL;
184*8040SBaban.Kenkre@Sun.COM 	char			**name_v, **dn_v, *domain = NULL;
185*8040SBaban.Kenkre@Sun.COM 	char			**gecos_v, **shell_v;
186*8040SBaban.Kenkre@Sun.COM 	char			**homedir_v = NULL, *homedir = NULL;
187*8040SBaban.Kenkre@Sun.COM 	char			*NULL_STR = "";
188*8040SBaban.Kenkre@Sun.COM 
189*8040SBaban.Kenkre@Sun.COM 	if (result == NULL)
190*8040SBaban.Kenkre@Sun.COM 		return (NSS_STR_PARSE_PARSE);
191*8040SBaban.Kenkre@Sun.COM 	entry = adutils_getfirstentry(result);
192*8040SBaban.Kenkre@Sun.COM 	nss_result = NSS_STR_PARSE_PARSE;
193*8040SBaban.Kenkre@Sun.COM 
194*8040SBaban.Kenkre@Sun.COM 	/* Create handles for idmap service */
195*8040SBaban.Kenkre@Sun.COM 	if (be->ih == NULL && idmap_init(&be->ih) != 0)
196*8040SBaban.Kenkre@Sun.COM 		goto result_pwd2str;
197*8040SBaban.Kenkre@Sun.COM 	if (idmap_get_create(be->ih, &ig) != 0)
198*8040SBaban.Kenkre@Sun.COM 		goto result_pwd2str;
199*8040SBaban.Kenkre@Sun.COM 
200*8040SBaban.Kenkre@Sun.COM 	/* Get name */
201*8040SBaban.Kenkre@Sun.COM 	name_v = adutils_getattr(entry, _PWD_SAN);
202*8040SBaban.Kenkre@Sun.COM 	if (name_v == NULL || name_v[0] == NULL || *name_v[0] == '\0')
203*8040SBaban.Kenkre@Sun.COM 		goto result_pwd2str;
204*8040SBaban.Kenkre@Sun.COM 
205*8040SBaban.Kenkre@Sun.COM 	/* Get domain */
206*8040SBaban.Kenkre@Sun.COM 	dn_v = adutils_getattr(entry, _PWD_DN);
207*8040SBaban.Kenkre@Sun.COM 	if (dn_v == NULL || dn_v[0] == NULL || *dn_v[0] == '\0')
208*8040SBaban.Kenkre@Sun.COM 		goto result_pwd2str;
209*8040SBaban.Kenkre@Sun.COM 	domain = adutils_dn2dns(dn_v[0]);
210*8040SBaban.Kenkre@Sun.COM 
211*8040SBaban.Kenkre@Sun.COM 	/* Get objectSID (in text format) */
212*8040SBaban.Kenkre@Sun.COM 	sid_v = adutils_getattr(entry, _PWD_OBJSID);
213*8040SBaban.Kenkre@Sun.COM 	if (sid_v == NULL || sid_v[0] == NULL || *sid_v[0] == '\0')
214*8040SBaban.Kenkre@Sun.COM 		goto result_pwd2str;
215*8040SBaban.Kenkre@Sun.COM 
216*8040SBaban.Kenkre@Sun.COM 	/* Break SID into prefix and rid */
217*8040SBaban.Kenkre@Sun.COM 	if ((ptr = strrchr(sid_v[0], '-')) == NULL)
218*8040SBaban.Kenkre@Sun.COM 		goto result_pwd2str;
219*8040SBaban.Kenkre@Sun.COM 	*ptr = '\0';
220*8040SBaban.Kenkre@Sun.COM 	end = ++ptr;
221*8040SBaban.Kenkre@Sun.COM 	tmp = strtoul(ptr, &end, 10);
222*8040SBaban.Kenkre@Sun.COM 	if (end == ptr || tmp > UINT32_MAX)
223*8040SBaban.Kenkre@Sun.COM 		goto result_pwd2str;
224*8040SBaban.Kenkre@Sun.COM 	urid = (uint32_t)tmp;
225*8040SBaban.Kenkre@Sun.COM 
226*8040SBaban.Kenkre@Sun.COM 	/* We already have uid -- no need to call idmapd */
227*8040SBaban.Kenkre@Sun.COM 	if (be->db_type == NSS_AD_DB_PASSWD_BYUID)
228*8040SBaban.Kenkre@Sun.COM 		uid = argp->key.uid;
229*8040SBaban.Kenkre@Sun.COM 	else
230*8040SBaban.Kenkre@Sun.COM 		uid = be->uid;
231*8040SBaban.Kenkre@Sun.COM 
232*8040SBaban.Kenkre@Sun.COM 	/* Get primaryGroupID */
233*8040SBaban.Kenkre@Sun.COM 	pgid_v = adutils_getattr(entry, _PWD_PRIMARYGROUPID);
234*8040SBaban.Kenkre@Sun.COM 	if (pgid_v == NULL || pgid_v[0] == NULL || *pgid_v[0] == '\0')
235*8040SBaban.Kenkre@Sun.COM 		/*
236*8040SBaban.Kenkre@Sun.COM 		 * If primaryGroupID is not found then we request
237*8040SBaban.Kenkre@Sun.COM 		 * a GID to be mapped to the given user's objectSID
238*8040SBaban.Kenkre@Sun.COM 		 * (diagonal mapping) and use this GID as the primary
239*8040SBaban.Kenkre@Sun.COM 		 * GID for the entry.
240*8040SBaban.Kenkre@Sun.COM 		 */
241*8040SBaban.Kenkre@Sun.COM 		grid = urid;
242*8040SBaban.Kenkre@Sun.COM 	else {
243*8040SBaban.Kenkre@Sun.COM 		end = pgid_v[0];
244*8040SBaban.Kenkre@Sun.COM 		tmp = strtoul(pgid_v[0], &end, 10);
245*8040SBaban.Kenkre@Sun.COM 		if (end == pgid_v[0] || tmp > UINT32_MAX)
246*8040SBaban.Kenkre@Sun.COM 			goto result_pwd2str;
247*8040SBaban.Kenkre@Sun.COM 		grid = (uint32_t)tmp;
248*8040SBaban.Kenkre@Sun.COM 	}
249*8040SBaban.Kenkre@Sun.COM 
250*8040SBaban.Kenkre@Sun.COM 	/* Map group SID to GID using idmap service */
251*8040SBaban.Kenkre@Sun.COM 	if (idmap_get_gidbysid(ig, sid_v[0], grid, 0, &gid, &gstat) != 0)
252*8040SBaban.Kenkre@Sun.COM 		goto result_pwd2str;
253*8040SBaban.Kenkre@Sun.COM 	if (idmap_get_mappings(ig) != 0 || gstat != 0) {
254*8040SBaban.Kenkre@Sun.COM 		RESET_ERRNO();
255*8040SBaban.Kenkre@Sun.COM 		goto result_pwd2str;
256*8040SBaban.Kenkre@Sun.COM 	}
257*8040SBaban.Kenkre@Sun.COM 
258*8040SBaban.Kenkre@Sun.COM 	/* Get gecos, homedirectory and shell information if available */
259*8040SBaban.Kenkre@Sun.COM 	gecos_v = adutils_getattr(entry, _PWD_CN);
260*8040SBaban.Kenkre@Sun.COM 	if (gecos_v == NULL || gecos_v[0] == NULL || *gecos_v[0] == '\0')
261*8040SBaban.Kenkre@Sun.COM 		gecos_v = &NULL_STR;
262*8040SBaban.Kenkre@Sun.COM 
263*8040SBaban.Kenkre@Sun.COM 	homedir_v = adutils_getattr(entry, _PWD_HOMEDIRECTORY);
264*8040SBaban.Kenkre@Sun.COM 	if (homedir_v == NULL || homedir_v[0] == NULL || *homedir_v[0] == '\0')
265*8040SBaban.Kenkre@Sun.COM 		homedir = NULL_STR;
266*8040SBaban.Kenkre@Sun.COM 	else if ((homedir = process_homedir(homedir_v[0])) == NULL)
267*8040SBaban.Kenkre@Sun.COM 		homedir = NULL_STR;
268*8040SBaban.Kenkre@Sun.COM 
269*8040SBaban.Kenkre@Sun.COM 	shell_v = adutils_getattr(entry, _PWD_LOGINSHELL);
270*8040SBaban.Kenkre@Sun.COM 	if (shell_v == NULL || shell_v[0] == NULL || *shell_v[0] == '\0')
271*8040SBaban.Kenkre@Sun.COM 		shell_v = &NULL_STR;
272*8040SBaban.Kenkre@Sun.COM 
273*8040SBaban.Kenkre@Sun.COM 	if (update_buffer(be, argp, name_v[0], domain, uid, gid,
274*8040SBaban.Kenkre@Sun.COM 	    gecos_v[0], homedir, shell_v[0]) < 0)
275*8040SBaban.Kenkre@Sun.COM 		nss_result = NSS_STR_PARSE_ERANGE;
276*8040SBaban.Kenkre@Sun.COM 	else
277*8040SBaban.Kenkre@Sun.COM 		nss_result = NSS_STR_PARSE_SUCCESS;
278*8040SBaban.Kenkre@Sun.COM 
279*8040SBaban.Kenkre@Sun.COM result_pwd2str:
280*8040SBaban.Kenkre@Sun.COM 	idmap_get_destroy(ig);
281*8040SBaban.Kenkre@Sun.COM 	(void) idmap_fini(be->ih);
282*8040SBaban.Kenkre@Sun.COM 	be->ih = NULL;
283*8040SBaban.Kenkre@Sun.COM 	(void) adutils_freeresult(&be->result);
284*8040SBaban.Kenkre@Sun.COM 	free(domain);
285*8040SBaban.Kenkre@Sun.COM 	if (homedir != NULL_STR && homedir_v != NULL &&
286*8040SBaban.Kenkre@Sun.COM 	    homedir != homedir_v[0])
287*8040SBaban.Kenkre@Sun.COM 		free(homedir);
288*8040SBaban.Kenkre@Sun.COM 	return ((int)nss_result);
289*8040SBaban.Kenkre@Sun.COM }
290*8040SBaban.Kenkre@Sun.COM 
291*8040SBaban.Kenkre@Sun.COM /*
292*8040SBaban.Kenkre@Sun.COM  * getbyname gets a passwd entry by winname. This function constructs an ldap
293*8040SBaban.Kenkre@Sun.COM  * search filter using the name invocation parameter and the getpwnam search
294*8040SBaban.Kenkre@Sun.COM  * filter defined. Once the filter is constructed, we search for a matching
295*8040SBaban.Kenkre@Sun.COM  * entry and marshal the data results into struct passwd for the frontend
296*8040SBaban.Kenkre@Sun.COM  * process. The function _nss_ad_passwd2ent performs the data marshaling.
297*8040SBaban.Kenkre@Sun.COM  */
298*8040SBaban.Kenkre@Sun.COM 
299*8040SBaban.Kenkre@Sun.COM static nss_status_t
300*8040SBaban.Kenkre@Sun.COM getbyname(ad_backend_ptr be, void *a)
301*8040SBaban.Kenkre@Sun.COM {
302*8040SBaban.Kenkre@Sun.COM 	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
303*8040SBaban.Kenkre@Sun.COM 	char		*searchfilter;
304*8040SBaban.Kenkre@Sun.COM 	char		name[SEARCHFILTERLEN];
305*8040SBaban.Kenkre@Sun.COM 	char		*dname;
306*8040SBaban.Kenkre@Sun.COM 	int		filterlen, namelen;
307*8040SBaban.Kenkre@Sun.COM 	int		flag;
308*8040SBaban.Kenkre@Sun.COM 	nss_status_t	stat;
309*8040SBaban.Kenkre@Sun.COM 	idmap_stat	idmaprc;
310*8040SBaban.Kenkre@Sun.COM 	uid_t		uid;
311*8040SBaban.Kenkre@Sun.COM 	gid_t		gid;
312*8040SBaban.Kenkre@Sun.COM 	int		is_user, is_wuser, try_idmap;
313*8040SBaban.Kenkre@Sun.COM 	idmap_handle_t	*ih;
314*8040SBaban.Kenkre@Sun.COM 
315*8040SBaban.Kenkre@Sun.COM 	be->db_type = NSS_AD_DB_PASSWD_BYNAME;
316*8040SBaban.Kenkre@Sun.COM 
317*8040SBaban.Kenkre@Sun.COM 	/* Sanitize name so that it can be used in our LDAP filter */
318*8040SBaban.Kenkre@Sun.COM 	if (_ldap_filter_name(name, argp->key.name, sizeof (name)) != 0)
319*8040SBaban.Kenkre@Sun.COM 		return ((nss_status_t)NSS_NOTFOUND);
320*8040SBaban.Kenkre@Sun.COM 
321*8040SBaban.Kenkre@Sun.COM 	if ((dname = strchr(name, '@')) == NULL)
322*8040SBaban.Kenkre@Sun.COM 		return ((nss_status_t)NSS_NOTFOUND);
323*8040SBaban.Kenkre@Sun.COM 
324*8040SBaban.Kenkre@Sun.COM 	*dname = '\0';
325*8040SBaban.Kenkre@Sun.COM 	dname++;
326*8040SBaban.Kenkre@Sun.COM 
327*8040SBaban.Kenkre@Sun.COM 	/*
328*8040SBaban.Kenkre@Sun.COM 	 * Map the given name to UID using idmap service. If idmap
329*8040SBaban.Kenkre@Sun.COM 	 * call fails then this will save us doing AD discovery and
330*8040SBaban.Kenkre@Sun.COM 	 * AD lookup here.
331*8040SBaban.Kenkre@Sun.COM 	 */
332*8040SBaban.Kenkre@Sun.COM 	if (idmap_init(&be->ih) != IDMAP_SUCCESS)
333*8040SBaban.Kenkre@Sun.COM 		return ((nss_status_t)NSS_NOTFOUND);
334*8040SBaban.Kenkre@Sun.COM 	flag = (strcasecmp(dname, WK_DOMAIN) == 0) ?
335*8040SBaban.Kenkre@Sun.COM 	    IDMAP_REQ_FLG_WK_OR_LOCAL_SIDS_ONLY : 0;
336*8040SBaban.Kenkre@Sun.COM 	is_wuser = -1;
337*8040SBaban.Kenkre@Sun.COM 	is_user = 1;
338*8040SBaban.Kenkre@Sun.COM 	if (idmap_get_w2u_mapping(be->ih, NULL, NULL, name,
339*8040SBaban.Kenkre@Sun.COM 	    dname, flag, &is_user, &is_wuser, &be->uid, NULL,
340*8040SBaban.Kenkre@Sun.COM 	    NULL, NULL) != IDMAP_SUCCESS) {
341*8040SBaban.Kenkre@Sun.COM 		(void) idmap_fini(be->ih);
342*8040SBaban.Kenkre@Sun.COM 		be->ih = NULL;
343*8040SBaban.Kenkre@Sun.COM 		RESET_ERRNO();
344*8040SBaban.Kenkre@Sun.COM 		return ((nss_status_t)NSS_NOTFOUND);
345*8040SBaban.Kenkre@Sun.COM 	}
346*8040SBaban.Kenkre@Sun.COM 
347*8040SBaban.Kenkre@Sun.COM 	/* If this is not a Well-Known SID then try AD lookup. */
348*8040SBaban.Kenkre@Sun.COM 	if (strcasecmp(dname, WK_DOMAIN) != 0) {
349*8040SBaban.Kenkre@Sun.COM 		/* Assemble filter using the given name */
350*8040SBaban.Kenkre@Sun.COM 		namelen = strlen(name);
351*8040SBaban.Kenkre@Sun.COM 		filterlen = snprintf(NULL, 0, _F_GETPWNAM, namelen, name) + 1;
352*8040SBaban.Kenkre@Sun.COM 		if ((searchfilter = (char *)malloc(filterlen)) == NULL)
353*8040SBaban.Kenkre@Sun.COM 			return ((nss_status_t)NSS_NOTFOUND);
354*8040SBaban.Kenkre@Sun.COM 		(void) snprintf(searchfilter, filterlen, _F_GETPWNAM,
355*8040SBaban.Kenkre@Sun.COM 		    namelen, name);
356*8040SBaban.Kenkre@Sun.COM 		stat = _nss_ad_lookup(be, argp, _PASSWD, searchfilter,
357*8040SBaban.Kenkre@Sun.COM 		    dname, &try_idmap);
358*8040SBaban.Kenkre@Sun.COM 		free(searchfilter);
359*8040SBaban.Kenkre@Sun.COM 
360*8040SBaban.Kenkre@Sun.COM 		if (!try_idmap) {
361*8040SBaban.Kenkre@Sun.COM 			(void) idmap_fini(be->ih);
362*8040SBaban.Kenkre@Sun.COM 			be->ih = NULL;
363*8040SBaban.Kenkre@Sun.COM 			return (stat);
364*8040SBaban.Kenkre@Sun.COM 		}
365*8040SBaban.Kenkre@Sun.COM 
366*8040SBaban.Kenkre@Sun.COM 	}
367*8040SBaban.Kenkre@Sun.COM 
368*8040SBaban.Kenkre@Sun.COM 	/*
369*8040SBaban.Kenkre@Sun.COM 	 * Either this is a Well-Known SID or AD lookup failed. Map
370*8040SBaban.Kenkre@Sun.COM 	 * the given name to GID using idmap service and construct
371*8040SBaban.Kenkre@Sun.COM 	 * the passwd entry.
372*8040SBaban.Kenkre@Sun.COM 	 */
373*8040SBaban.Kenkre@Sun.COM 	is_wuser = -1;
374*8040SBaban.Kenkre@Sun.COM 	is_user = 0; /* Map name to primary gid */
375*8040SBaban.Kenkre@Sun.COM 	idmaprc = idmap_get_w2u_mapping(be->ih, NULL, NULL, name, dname,
376*8040SBaban.Kenkre@Sun.COM 	    flag, &is_user, &is_wuser, &gid, NULL, NULL, NULL);
377*8040SBaban.Kenkre@Sun.COM 	(void) idmap_fini(be->ih);
378*8040SBaban.Kenkre@Sun.COM 	be->ih = NULL;
379*8040SBaban.Kenkre@Sun.COM 	if (idmaprc != IDMAP_SUCCESS) {
380*8040SBaban.Kenkre@Sun.COM 		RESET_ERRNO();
381*8040SBaban.Kenkre@Sun.COM 		return ((nss_status_t)NSS_NOTFOUND);
382*8040SBaban.Kenkre@Sun.COM 	}
383*8040SBaban.Kenkre@Sun.COM 
384*8040SBaban.Kenkre@Sun.COM 	/* Create passwd(4) style string */
385*8040SBaban.Kenkre@Sun.COM 	if (update_buffer(be, argp, name, dname,
386*8040SBaban.Kenkre@Sun.COM 	    be->uid, gid, "", "", "") < 0)
387*8040SBaban.Kenkre@Sun.COM 		return ((nss_status_t)NSS_NOTFOUND);
388*8040SBaban.Kenkre@Sun.COM 
389*8040SBaban.Kenkre@Sun.COM 	/* Marshall the data, sanitize the return status and return */
390*8040SBaban.Kenkre@Sun.COM 	stat = _nss_ad_marshall_data(be, argp);
391*8040SBaban.Kenkre@Sun.COM 	return (_nss_ad_sanitize_status(be, argp, stat));
392*8040SBaban.Kenkre@Sun.COM }
393*8040SBaban.Kenkre@Sun.COM 
394*8040SBaban.Kenkre@Sun.COM 
395*8040SBaban.Kenkre@Sun.COM /*
396*8040SBaban.Kenkre@Sun.COM  * getbyuid gets a passwd entry by uid number. This function constructs an ldap
397*8040SBaban.Kenkre@Sun.COM  * search filter using the uid invocation parameter and the getpwuid search
398*8040SBaban.Kenkre@Sun.COM  * filter defined. Once the filter is constructed, we search for a matching
399*8040SBaban.Kenkre@Sun.COM  * entry and marshal the data results into struct passwd for the frontend
400*8040SBaban.Kenkre@Sun.COM  * process. The function _nss_ad_passwd2ent performs the data marshaling.
401*8040SBaban.Kenkre@Sun.COM  */
402*8040SBaban.Kenkre@Sun.COM 
403*8040SBaban.Kenkre@Sun.COM static nss_status_t
404*8040SBaban.Kenkre@Sun.COM getbyuid(ad_backend_ptr be, void *a)
405*8040SBaban.Kenkre@Sun.COM {
406*8040SBaban.Kenkre@Sun.COM 	nss_XbyY_args_t		*argp = (nss_XbyY_args_t *)a;
407*8040SBaban.Kenkre@Sun.COM 	char			searchfilter[ADUTILS_MAXHEXBINSID + 14];
408*8040SBaban.Kenkre@Sun.COM 	char			*sidprefix = NULL;
409*8040SBaban.Kenkre@Sun.COM 	idmap_rid_t		rid;
410*8040SBaban.Kenkre@Sun.COM 	char			cbinsid[ADUTILS_MAXHEXBINSID + 1];
411*8040SBaban.Kenkre@Sun.COM 	char			*winname = NULL, *windomain = NULL;
412*8040SBaban.Kenkre@Sun.COM 	int			is_user, is_wuser;
413*8040SBaban.Kenkre@Sun.COM 	gid_t			gid;
414*8040SBaban.Kenkre@Sun.COM 	idmap_stat		idmaprc;
415*8040SBaban.Kenkre@Sun.COM 	int			ret, try_idmap;
416*8040SBaban.Kenkre@Sun.COM 	nss_status_t		stat;
417*8040SBaban.Kenkre@Sun.COM 
418*8040SBaban.Kenkre@Sun.COM 	be->db_type = NSS_AD_DB_PASSWD_BYUID;
419*8040SBaban.Kenkre@Sun.COM 
420*8040SBaban.Kenkre@Sun.COM 	stat = (nss_status_t)NSS_NOTFOUND;
421*8040SBaban.Kenkre@Sun.COM 
422*8040SBaban.Kenkre@Sun.COM 	/* nss_ad does not support non ephemeral uids */
423*8040SBaban.Kenkre@Sun.COM 	if (argp->key.uid <= MAXUID)
424*8040SBaban.Kenkre@Sun.COM 		goto out;
425*8040SBaban.Kenkre@Sun.COM 
426*8040SBaban.Kenkre@Sun.COM 	/* Map the given UID to a SID using the idmap service */
427*8040SBaban.Kenkre@Sun.COM 	if (idmap_init(&be->ih) != 0)
428*8040SBaban.Kenkre@Sun.COM 		goto out;
429*8040SBaban.Kenkre@Sun.COM 	if (idmap_get_u2w_mapping(be->ih, &argp->key.uid, NULL, 0,
430*8040SBaban.Kenkre@Sun.COM 	    1, NULL, &sidprefix, &rid, &winname, &windomain,
431*8040SBaban.Kenkre@Sun.COM 	    NULL, NULL) != 0) {
432*8040SBaban.Kenkre@Sun.COM 		RESET_ERRNO();
433*8040SBaban.Kenkre@Sun.COM 		goto out;
434*8040SBaban.Kenkre@Sun.COM 	}
435*8040SBaban.Kenkre@Sun.COM 
436*8040SBaban.Kenkre@Sun.COM 	/*
437*8040SBaban.Kenkre@Sun.COM 	 * NULL winname implies a local SID or unresolvable SID both of
438*8040SBaban.Kenkre@Sun.COM 	 * which cannot be used to generated passwd(4) entry
439*8040SBaban.Kenkre@Sun.COM 	 */
440*8040SBaban.Kenkre@Sun.COM 	if (winname == NULL)
441*8040SBaban.Kenkre@Sun.COM 		goto out;
442*8040SBaban.Kenkre@Sun.COM 
443*8040SBaban.Kenkre@Sun.COM 	/* If this is not a Well-Known SID try AD lookup */
444*8040SBaban.Kenkre@Sun.COM 	if (windomain != NULL && strcasecmp(windomain, WK_DOMAIN) != 0) {
445*8040SBaban.Kenkre@Sun.COM 		if (adutils_txtsid2hexbinsid(sidprefix, &rid,
446*8040SBaban.Kenkre@Sun.COM 		    &cbinsid[0], sizeof (cbinsid)) != 0)
447*8040SBaban.Kenkre@Sun.COM 			goto out;
448*8040SBaban.Kenkre@Sun.COM 
449*8040SBaban.Kenkre@Sun.COM 		ret = snprintf(searchfilter, sizeof (searchfilter),
450*8040SBaban.Kenkre@Sun.COM 		    _F_GETPWUID, cbinsid);
451*8040SBaban.Kenkre@Sun.COM 		if (ret >= sizeof (searchfilter) || ret < 0)
452*8040SBaban.Kenkre@Sun.COM 			goto out;
453*8040SBaban.Kenkre@Sun.COM 
454*8040SBaban.Kenkre@Sun.COM 		stat = _nss_ad_lookup(be, argp, _PASSWD, searchfilter,
455*8040SBaban.Kenkre@Sun.COM 		    windomain, &try_idmap);
456*8040SBaban.Kenkre@Sun.COM 
457*8040SBaban.Kenkre@Sun.COM 		if (!try_idmap)
458*8040SBaban.Kenkre@Sun.COM 			goto out;
459*8040SBaban.Kenkre@Sun.COM 	}
460*8040SBaban.Kenkre@Sun.COM 
461*8040SBaban.Kenkre@Sun.COM 	/* Map winname to primary gid using idmap service */
462*8040SBaban.Kenkre@Sun.COM 	is_user = 0;
463*8040SBaban.Kenkre@Sun.COM 	is_wuser = -1;
464*8040SBaban.Kenkre@Sun.COM 	idmaprc = idmap_get_w2u_mapping(be->ih, NULL, NULL,
465*8040SBaban.Kenkre@Sun.COM 	    winname, windomain, 0, &is_user, &is_wuser, &gid,
466*8040SBaban.Kenkre@Sun.COM 	    NULL, NULL, NULL);
467*8040SBaban.Kenkre@Sun.COM 
468*8040SBaban.Kenkre@Sun.COM 	(void) idmap_fini(be->ih);
469*8040SBaban.Kenkre@Sun.COM 	be->ih = NULL;
470*8040SBaban.Kenkre@Sun.COM 
471*8040SBaban.Kenkre@Sun.COM 	if (idmaprc != IDMAP_SUCCESS) {
472*8040SBaban.Kenkre@Sun.COM 		RESET_ERRNO();
473*8040SBaban.Kenkre@Sun.COM 		goto out;
474*8040SBaban.Kenkre@Sun.COM 	}
475*8040SBaban.Kenkre@Sun.COM 
476*8040SBaban.Kenkre@Sun.COM 	/* Create passwd(4) style string */
477*8040SBaban.Kenkre@Sun.COM 	if (update_buffer(be, argp, winname, windomain,
478*8040SBaban.Kenkre@Sun.COM 	    argp->key.uid, gid, "", "", "") < 0)
479*8040SBaban.Kenkre@Sun.COM 		goto out;
480*8040SBaban.Kenkre@Sun.COM 
481*8040SBaban.Kenkre@Sun.COM 	/* Marshall the data, sanitize the return status and return */
482*8040SBaban.Kenkre@Sun.COM 	stat = _nss_ad_marshall_data(be, argp);
483*8040SBaban.Kenkre@Sun.COM 	stat = _nss_ad_sanitize_status(be, argp, stat);
484*8040SBaban.Kenkre@Sun.COM 
485*8040SBaban.Kenkre@Sun.COM out:
486*8040SBaban.Kenkre@Sun.COM 	idmap_free(sidprefix);
487*8040SBaban.Kenkre@Sun.COM 	idmap_free(winname);
488*8040SBaban.Kenkre@Sun.COM 	idmap_free(windomain);
489*8040SBaban.Kenkre@Sun.COM 	(void) idmap_fini(be->ih);
490*8040SBaban.Kenkre@Sun.COM 	be->ih = NULL;
491*8040SBaban.Kenkre@Sun.COM 	return (stat);
492*8040SBaban.Kenkre@Sun.COM }
493*8040SBaban.Kenkre@Sun.COM 
494*8040SBaban.Kenkre@Sun.COM static ad_backend_op_t passwd_ops[] = {
495*8040SBaban.Kenkre@Sun.COM 	_nss_ad_destr,
496*8040SBaban.Kenkre@Sun.COM 	_nss_ad_endent,
497*8040SBaban.Kenkre@Sun.COM 	_nss_ad_setent,
498*8040SBaban.Kenkre@Sun.COM 	_nss_ad_getent,
499*8040SBaban.Kenkre@Sun.COM 	getbyname,
500*8040SBaban.Kenkre@Sun.COM 	getbyuid
501*8040SBaban.Kenkre@Sun.COM };
502*8040SBaban.Kenkre@Sun.COM 
503*8040SBaban.Kenkre@Sun.COM /*
504*8040SBaban.Kenkre@Sun.COM  * _nss_ad_passwd_constr is where life begins. This function calls the
505*8040SBaban.Kenkre@Sun.COM  * generic AD constructor function to define and build the abstract
506*8040SBaban.Kenkre@Sun.COM  * data types required to support AD operations.
507*8040SBaban.Kenkre@Sun.COM  */
508*8040SBaban.Kenkre@Sun.COM 
509*8040SBaban.Kenkre@Sun.COM /*ARGSUSED0*/
510*8040SBaban.Kenkre@Sun.COM nss_backend_t *
511*8040SBaban.Kenkre@Sun.COM _nss_ad_passwd_constr(const char *dummy1, const char *dummy2,
512*8040SBaban.Kenkre@Sun.COM 			const char *dummy3)
513*8040SBaban.Kenkre@Sun.COM {
514*8040SBaban.Kenkre@Sun.COM 
515*8040SBaban.Kenkre@Sun.COM 	return ((nss_backend_t *)_nss_ad_constr(passwd_ops,
516*8040SBaban.Kenkre@Sun.COM 	    sizeof (passwd_ops)/sizeof (passwd_ops[0]),
517*8040SBaban.Kenkre@Sun.COM 	    _PASSWD, pwd_attrs, _nss_ad_passwd2str));
518*8040SBaban.Kenkre@Sun.COM }
519