1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <pwd.h>
29 #include "ldap_common.h"
30 
31 /* passwd attributes filters */
32 #define	_PWD_CN			"cn"
33 #define	_PWD_UID		"uid"
34 #define	_PWD_USERPASSWORD	"userpassword"
35 #define	_PWD_UIDNUMBER		"uidnumber"
36 #define	_PWD_GIDNUMBER		"gidnumber"
37 #define	_PWD_GECOS		"gecos"
38 #define	_PWD_DESCRIPTION	"description"
39 #define	_PWD_HOMEDIRECTORY	"homedirectory"
40 #define	_PWD_LOGINSHELL		"loginshell"
41 
42 
43 #define	_F_GETPWNAM		"(&(objectClass=posixAccount)(uid=%s))"
44 #define	_F_GETPWNAM_SSD		"(&(%%s)(uid=%s))"
45 #define	_F_GETPWUID		"(&(objectClass=posixAccount)(uidNumber=%ld))"
46 #define	_F_GETPWUID_SSD		"(&(%%s)(uidNumber=%ld))"
47 
48 static const char *pwd_attrs[] = {
49 	_PWD_CN,
50 	_PWD_UID,
51 	_PWD_UIDNUMBER,
52 	_PWD_GIDNUMBER,
53 	_PWD_GECOS,
54 	_PWD_DESCRIPTION,
55 	_PWD_HOMEDIRECTORY,
56 	_PWD_LOGINSHELL,
57 	(char *)NULL
58 };
59 
60 /*
61  * _nss_ldap_passwd2str is the data marshaling method for the passwd getXbyY
62  * (e.g., getbyuid(), getbyname(), getpwent()) backend processes. This method is
63  * called after a successful ldap search has been performed. This method will
64  * parse the ldap search values into the file format.
65  * e.g.
66  *
67  * nobody:x:60001:60001:Nobody:/:
68  *
69  */
70 static int
71 _nss_ldap_passwd2str(ldap_backend_ptr be, nss_XbyY_args_t *argp)
72 {
73 	int		nss_result;
74 	int		buflen = 0;
75 	unsigned long	str_len = 0L;
76 	char		*buffer = NULL;
77 	ns_ldap_result_t	*result = be->result;
78 	ns_ldap_entry_t	*entry;
79 	char		**uid_v, **uidn_v, **gidn_v;
80 	char		**gecos_v, **homedir_v, **shell_v;
81 	char		*NULL_STR = "";
82 
83 	if (result == NULL)
84 		return (NSS_STR_PARSE_PARSE);
85 
86 	entry = result->entry;
87 
88 	buflen = argp->buf.buflen;
89 	buffer = argp->buf.buffer;
90 
91 	nss_result = NSS_STR_PARSE_SUCCESS;
92 	(void) memset(buffer, 0, buflen);
93 
94 	/* 8 = 6 ':' + 1 '\0' + 1 'x' */
95 	buflen -=  8;
96 
97 	uid_v = __ns_ldap_getAttr(entry, _PWD_UID);
98 	uidn_v = __ns_ldap_getAttr(entry, _PWD_UIDNUMBER);
99 	gidn_v = __ns_ldap_getAttr(entry, _PWD_GIDNUMBER);
100 	if (uid_v == NULL || uidn_v == NULL || gidn_v == NULL ||
101 		uid_v[0] == NULL || uidn_v[0] == NULL || gidn_v[0] == NULL) {
102 		nss_result = NSS_STR_PARSE_PARSE;
103 		goto result_pwd2str;
104 	}
105 	str_len = strlen(uid_v[0]) + strlen(uidn_v[0]) + strlen(gidn_v[0]);
106 	if (str_len >  buflen) {
107 		nss_result = NSS_STR_PARSE_ERANGE;
108 		goto result_pwd2str;
109 	}
110 
111 	gecos_v = __ns_ldap_getAttr(entry, _PWD_GECOS);
112 	if (gecos_v == NULL || gecos_v[0] == NULL || *gecos_v[0] == '\0')
113 		gecos_v = &NULL_STR;
114 	else
115 		str_len += strlen(gecos_v[0]);
116 
117 	homedir_v = __ns_ldap_getAttr(entry, _PWD_HOMEDIRECTORY);
118 	if (homedir_v == NULL || homedir_v[0] == NULL || *homedir_v[0] == '\0')
119 		homedir_v = &NULL_STR;
120 	else
121 		str_len += strlen(homedir_v[0]);
122 
123 	shell_v = __ns_ldap_getAttr(entry, _PWD_LOGINSHELL);
124 	if (shell_v == NULL || shell_v[0] == NULL || *shell_v[0] == '\0')
125 		shell_v = &NULL_STR;
126 	else
127 		str_len += strlen(shell_v[0]);
128 
129 	if (str_len >  buflen) {
130 		nss_result = NSS_STR_PARSE_ERANGE;
131 		goto result_pwd2str;
132 	}
133 
134 	if (argp->buf.result != NULL) {
135 		be->buflen = str_len + 8;
136 		be->buffer = malloc(be->buflen);
137 		if (be->buffer == NULL) {
138 			nss_result = (int)NSS_STR_PARSE_ERANGE;
139 			goto result_pwd2str;
140 		}
141 
142 		(void) snprintf(be->buffer, be->buflen,
143 				"%s:%s:%s:%s:%s:%s:%s",
144 			uid_v[0], "x", uidn_v[0], gidn_v[0],
145 			gecos_v[0], homedir_v[0], shell_v[0]);
146 	} else {
147 		(void) snprintf(argp->buf.buffer, (str_len + 8),
148 				"%s:%s:%s:%s:%s:%s:%s",
149 			uid_v[0], "x", uidn_v[0], gidn_v[0],
150 			gecos_v[0], homedir_v[0], shell_v[0]);
151 
152 	}
153 
154 result_pwd2str:
155 
156 	(void) __ns_ldap_freeResult(&be->result);
157 	return ((int)nss_result);
158 }
159 
160 /*
161  * getbyname gets a passwd entry by uid name. This function constructs an ldap
162  * search filter using the name invocation parameter and the getpwnam search
163  * filter defined. Once the filter is constructed, we search for a matching
164  * entry and marshal the data results into struct passwd for the frontend
165  * process. The function _nss_ldap_passwd2ent performs the data marshaling.
166  */
167 
168 static nss_status_t
169 getbyname(ldap_backend_ptr be, void *a)
170 {
171 	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
172 	char		searchfilter[SEARCHFILTERLEN];
173 	char		userdata[SEARCHFILTERLEN];
174 	char		name[SEARCHFILTERLEN];
175 	int		ret;
176 
177 	if (_ldap_filter_name(name, argp->key.name, sizeof (name)) != 0)
178 		return ((nss_status_t)NSS_NOTFOUND);
179 
180 	ret = snprintf(searchfilter, sizeof (searchfilter), _F_GETPWNAM, name);
181 	if (ret >= sizeof (searchfilter) || ret < 0)
182 		return ((nss_status_t)NSS_NOTFOUND);
183 
184 	ret = snprintf(userdata, sizeof (userdata), _F_GETPWNAM_SSD, name);
185 	if (ret >= sizeof (userdata) || ret < 0)
186 		return ((nss_status_t)NSS_NOTFOUND);
187 
188 	return ((nss_status_t)_nss_ldap_lookup(be, argp,
189 		_PASSWD, searchfilter, NULL,
190 		_merge_SSD_filter, userdata));
191 }
192 
193 
194 /*
195  * getbyuid gets a passwd entry by uid number. This function constructs an ldap
196  * search filter using the uid invocation parameter and the getpwuid search
197  * filter defined. Once the filter is constructed, we search for a matching
198  * entry and marshal the data results into struct passwd for the frontend
199  * process. The function _nss_ldap_passwd2ent performs the data marshaling.
200  */
201 
202 static nss_status_t
203 getbyuid(ldap_backend_ptr be, void *a)
204 {
205 	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
206 	char		searchfilter[SEARCHFILTERLEN];
207 	char		userdata[SEARCHFILTERLEN];
208 	int		ret;
209 
210 	ret = snprintf(searchfilter, sizeof (searchfilter),
211 	    _F_GETPWUID, (long)argp->key.uid);
212 	if (ret >= sizeof (searchfilter) || ret < 0)
213 		return ((nss_status_t)NSS_NOTFOUND);
214 
215 	ret = snprintf(userdata, sizeof (userdata),
216 	    _F_GETPWUID_SSD, (long)argp->key.uid);
217 	if (ret >= sizeof (userdata) || ret < 0)
218 		return ((nss_status_t)NSS_NOTFOUND);
219 
220 	return ((nss_status_t)_nss_ldap_lookup(be, argp,
221 		_PASSWD, searchfilter, NULL,
222 		_merge_SSD_filter, userdata));
223 }
224 
225 static ldap_backend_op_t passwd_ops[] = {
226 	_nss_ldap_destr,
227 	_nss_ldap_endent,
228 	_nss_ldap_setent,
229 	_nss_ldap_getent,
230 	getbyname,
231 	getbyuid
232 };
233 
234 
235 /*
236  * _nss_ldap_passwd_constr is where life begins. This function calls the
237  * generic ldap constructor function to define and build the abstract
238  * data types required to support ldap operations.
239  */
240 
241 /*ARGSUSED0*/
242 nss_backend_t *
243 _nss_ldap_passwd_constr(const char *dummy1, const char *dummy2,
244 			const char *dummy3)
245 {
246 
247 	return ((nss_backend_t *)_nss_ldap_constr(passwd_ops,
248 		    sizeof (passwd_ops)/sizeof (passwd_ops[0]),
249 		    _PASSWD, pwd_attrs, _nss_ldap_passwd2str));
250 }
251