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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <pwd.h>
27 #include "ldap_common.h"
28 
29 /* passwd attributes filters */
30 #define	_PWD_CN			"cn"
31 #define	_PWD_UID		"uid"
32 #define	_PWD_USERPASSWORD	"userpassword"
33 #define	_PWD_UIDNUMBER		"uidnumber"
34 #define	_PWD_GIDNUMBER		"gidnumber"
35 #define	_PWD_GECOS		"gecos"
36 #define	_PWD_DESCRIPTION	"description"
37 #define	_PWD_HOMEDIRECTORY	"homedirectory"
38 #define	_PWD_LOGINSHELL		"loginshell"
39 
40 
41 #define	_F_GETPWNAM		"(&(objectClass=posixAccount)(uid=%s))"
42 #define	_F_GETPWNAM_SSD		"(&(%%s)(uid=%s))"
43 #define	_F_GETPWUID		"(&(objectClass=posixAccount)(uidNumber=%ld))"
44 #define	_F_GETPWUID_SSD		"(&(%%s)(uidNumber=%ld))"
45 
46 static const char *pwd_attrs[] = {
47 	_PWD_CN,
48 	_PWD_UID,
49 	_PWD_UIDNUMBER,
50 	_PWD_GIDNUMBER,
51 	_PWD_GECOS,
52 	_PWD_DESCRIPTION,
53 	_PWD_HOMEDIRECTORY,
54 	_PWD_LOGINSHELL,
55 	(char *)NULL
56 };
57 
58 /*
59  * _nss_ldap_passwd2str is the data marshaling method for the passwd getXbyY
60  * (e.g., getbyuid(), getbyname(), getpwent()) backend processes. This method is
61  * called after a successful ldap search has been performed. This method will
62  * parse the ldap search values into the file format.
63  * e.g.
64  *
65  * nobody:x:60001:60001:Nobody:/:
66  *
67  */
68 static int
_nss_ldap_passwd2str(ldap_backend_ptr be,nss_XbyY_args_t * argp)69 _nss_ldap_passwd2str(ldap_backend_ptr be, nss_XbyY_args_t *argp)
70 {
71 	int		nss_result;
72 	int		buflen = 0;
73 	unsigned long	str_len = 0L;
74 	char		*buffer = NULL;
75 	ns_ldap_result_t	*result = be->result;
76 	ns_ldap_entry_t	*entry;
77 	char		**uid_v, **uidn_v, **gidn_v;
78 	char		**gecos_v, **homedir_v, **shell_v;
79 	char		*NULL_STR = "";
80 	char		uid_nobody[NOBODY_STR_LEN];
81 	char		gid_nobody[NOBODY_STR_LEN], *end;
82 	char		*uid_nobody_v[1], *gid_nobody_v[1];
83 
84 	(void) snprintf(uid_nobody, sizeof (uid_nobody), "%u", UID_NOBODY);
85 	uid_nobody_v[0] = uid_nobody;
86 	(void) snprintf(gid_nobody, sizeof (gid_nobody), "%u", GID_NOBODY);
87 	gid_nobody_v[0] = gid_nobody;
88 
89 	if (result == NULL)
90 		return (NSS_STR_PARSE_PARSE);
91 
92 	entry = result->entry;
93 
94 	buflen = argp->buf.buflen;
95 	buffer = argp->buf.buffer;
96 
97 	nss_result = NSS_STR_PARSE_SUCCESS;
98 	(void) memset(buffer, 0, buflen);
99 
100 	/* 8 = 6 ':' + 1 '\0' + 1 'x' */
101 	buflen -=  8;
102 
103 	uid_v = __ns_ldap_getAttr(entry, _PWD_UID);
104 	uidn_v = __ns_ldap_getAttr(entry, _PWD_UIDNUMBER);
105 	gidn_v = __ns_ldap_getAttr(entry, _PWD_GIDNUMBER);
106 	if (uid_v == NULL || uidn_v == NULL || gidn_v == NULL ||
107 	    uid_v[0] == NULL || uidn_v[0] == NULL || gidn_v[0] == NULL) {
108 		nss_result = NSS_STR_PARSE_PARSE;
109 		goto result_pwd2str;
110 	}
111 	/* Validate UID and GID */
112 	if (strtoul(uidn_v[0], &end, 10) > MAXUID)
113 		uidn_v = uid_nobody_v;
114 	if (strtoul(gidn_v[0], &end, 10) > MAXUID)
115 		gidn_v = gid_nobody_v;
116 	str_len = strlen(uid_v[0]) + strlen(uidn_v[0]) + strlen(gidn_v[0]);
117 	if (str_len >  buflen) {
118 		nss_result = NSS_STR_PARSE_ERANGE;
119 		goto result_pwd2str;
120 	}
121 
122 	gecos_v = __ns_ldap_getAttr(entry, _PWD_GECOS);
123 	if (gecos_v == NULL || gecos_v[0] == NULL || *gecos_v[0] == '\0')
124 		gecos_v = &NULL_STR;
125 	else
126 		str_len += strlen(gecos_v[0]);
127 
128 	homedir_v = __ns_ldap_getAttr(entry, _PWD_HOMEDIRECTORY);
129 	if (homedir_v == NULL || homedir_v[0] == NULL || *homedir_v[0] == '\0')
130 		homedir_v = &NULL_STR;
131 	else
132 		str_len += strlen(homedir_v[0]);
133 
134 	shell_v = __ns_ldap_getAttr(entry, _PWD_LOGINSHELL);
135 	if (shell_v == NULL || shell_v[0] == NULL || *shell_v[0] == '\0')
136 		shell_v = &NULL_STR;
137 	else
138 		str_len += strlen(shell_v[0]);
139 
140 	if (str_len >  buflen) {
141 		nss_result = NSS_STR_PARSE_ERANGE;
142 		goto result_pwd2str;
143 	}
144 
145 	if (argp->buf.result != NULL) {
146 		be->buflen = str_len + 8;
147 		be->buffer = malloc(be->buflen);
148 		if (be->buffer == NULL) {
149 			nss_result = (int)NSS_STR_PARSE_ERANGE;
150 			goto result_pwd2str;
151 		}
152 
153 		(void) snprintf(be->buffer, be->buflen,
154 		    "%s:%s:%s:%s:%s:%s:%s",
155 		    uid_v[0], "x", uidn_v[0], gidn_v[0],
156 		    gecos_v[0], homedir_v[0], shell_v[0]);
157 	} else {
158 		(void) snprintf(argp->buf.buffer, (str_len + 8),
159 		    "%s:%s:%s:%s:%s:%s:%s",
160 		    uid_v[0], "x", uidn_v[0], gidn_v[0],
161 		    gecos_v[0], homedir_v[0], shell_v[0]);
162 	}
163 
164 result_pwd2str:
165 
166 	(void) __ns_ldap_freeResult(&be->result);
167 	return ((int)nss_result);
168 }
169 
170 /*
171  * getbyname gets a passwd entry by uid name. This function constructs an ldap
172  * search filter using the name invocation parameter and the getpwnam search
173  * filter defined. Once the filter is constructed, we search for a matching
174  * entry and marshal the data results into struct passwd for the frontend
175  * process. The function _nss_ldap_passwd2ent performs the data marshaling.
176  */
177 
178 static nss_status_t
getbyname(ldap_backend_ptr be,void * a)179 getbyname(ldap_backend_ptr be, void *a)
180 {
181 	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
182 	char		searchfilter[SEARCHFILTERLEN];
183 	char		userdata[SEARCHFILTERLEN];
184 	char		name[SEARCHFILTERLEN];
185 	int		ret;
186 
187 	if (_ldap_filter_name(name, argp->key.name, sizeof (name)) != 0)
188 		return ((nss_status_t)NSS_NOTFOUND);
189 
190 	ret = snprintf(searchfilter, sizeof (searchfilter), _F_GETPWNAM, name);
191 	if (ret >= sizeof (searchfilter) || ret < 0)
192 		return ((nss_status_t)NSS_NOTFOUND);
193 
194 	ret = snprintf(userdata, sizeof (userdata), _F_GETPWNAM_SSD, name);
195 	if (ret >= sizeof (userdata) || ret < 0)
196 		return ((nss_status_t)NSS_NOTFOUND);
197 
198 	return ((nss_status_t)_nss_ldap_lookup(be, argp,
199 	    _PASSWD, searchfilter, NULL, _merge_SSD_filter, userdata));
200 }
201 
202 
203 /*
204  * getbyuid gets a passwd entry by uid number. This function constructs an ldap
205  * search filter using the uid invocation parameter and the getpwuid search
206  * filter defined. Once the filter is constructed, we search for a matching
207  * entry and marshal the data results into struct passwd for the frontend
208  * process. The function _nss_ldap_passwd2ent performs the data marshaling.
209  */
210 
211 static nss_status_t
getbyuid(ldap_backend_ptr be,void * a)212 getbyuid(ldap_backend_ptr be, void *a)
213 {
214 	nss_XbyY_args_t	*argp = (nss_XbyY_args_t *)a;
215 	char		searchfilter[SEARCHFILTERLEN];
216 	char		userdata[SEARCHFILTERLEN];
217 	int		ret;
218 
219 	if (argp->key.uid > MAXUID)
220 		return ((nss_status_t)NSS_NOTFOUND);
221 
222 	ret = snprintf(searchfilter, sizeof (searchfilter),
223 	    _F_GETPWUID, (long)argp->key.uid);
224 	if (ret >= sizeof (searchfilter) || ret < 0)
225 		return ((nss_status_t)NSS_NOTFOUND);
226 
227 	ret = snprintf(userdata, sizeof (userdata),
228 	    _F_GETPWUID_SSD, (long)argp->key.uid);
229 	if (ret >= sizeof (userdata) || ret < 0)
230 		return ((nss_status_t)NSS_NOTFOUND);
231 
232 	return ((nss_status_t)_nss_ldap_lookup(be, argp,
233 	    _PASSWD, searchfilter, NULL, _merge_SSD_filter, userdata));
234 }
235 
236 static ldap_backend_op_t passwd_ops[] = {
237 	_nss_ldap_destr,
238 	_nss_ldap_endent,
239 	_nss_ldap_setent,
240 	_nss_ldap_getent,
241 	getbyname,
242 	getbyuid
243 };
244 
245 
246 /*
247  * _nss_ldap_passwd_constr is where life begins. This function calls the
248  * generic ldap constructor function to define and build the abstract
249  * data types required to support ldap operations.
250  */
251 
252 /*ARGSUSED0*/
253 nss_backend_t *
_nss_ldap_passwd_constr(const char * dummy1,const char * dummy2,const char * dummy3)254 _nss_ldap_passwd_constr(const char *dummy1, const char *dummy2,
255 			const char *dummy3)
256 {
257 
258 	return ((nss_backend_t *)_nss_ldap_constr(passwd_ops,
259 	    sizeof (passwd_ops)/sizeof (passwd_ops[0]),
260 	    _PASSWD, pwd_attrs, _nss_ldap_passwd2str));
261 }
262