2 * Copyright (c) 2002 Networks Associates Technology, Inc.
5 * This software was developed for the FreeBSD Project by ThinkSec AS and
6 * NAI Labs, the Security Research Division of Network Associates, Inc.
7 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
8 * DARPA CHATS research program.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. The name of the author may not be used to endorse or promote
19 * products derived from this software without specific prior written
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <netinet/in.h>
43 #include <netconfig.h>
50 #include <rpcsvc/ypclnt.h>
51 #include <rpcsvc/yppasswd.h>
54 #include "yppasswd_private.h"
56 static int yppasswd_remote(ypclnt_t *, const struct passwd *, const char *);
57 static int yppasswd_local(ypclnt_t *, const struct passwd *);
60 * Determines the availability of rpc.yppasswdd. Returns -1 for not
61 * available (or unable to determine), 0 for available, 1 for available in
65 ypclnt_havepasswdd(ypclnt_t *ypclnt)
67 struct netconfig *nc = NULL;
68 void *localhandle = 0;
72 /* check if rpc.yppasswdd is running */
73 if (getrpcport(ypclnt->server, YPPASSWDPROG,
74 YPPASSWDPROC_UPDATE, IPPROTO_UDP) == 0) {
75 ypclnt_error(ypclnt, __func__, "no rpc.yppasswdd on server");
79 /* if we're not root, use remote method */
83 /* try to connect to rpc.yppasswdd */
84 localhandle = setnetconfig();
85 while ((nc = getnetconfig(localhandle)) != NULL) {
86 if (nc->nc_protofmly != NULL &&
87 strcmp(nc->nc_protofmly, NC_LOOPBACK) == 0)
91 ypclnt_error(ypclnt, __func__,
92 "getnetconfig: %s", nc_sperror());
96 if ((clnt = clnt_tp_create(NULL, MASTER_YPPASSWDPROG,
97 MASTER_YPPASSWDVERS, nc)) == NULL) {
98 ypclnt_error(ypclnt, __func__,
99 "failed to connect to rpc.yppasswdd: %s",
100 clnt_spcreateerror(ypclnt->server));
110 endnetconfig(localhandle);
115 * Updates the NIS user information for the specified user.
118 ypclnt_passwd(ypclnt_t *ypclnt, const struct passwd *pwd, const char *passwd)
120 switch (ypclnt_havepasswdd(ypclnt)) {
122 YPCLNT_DEBUG("using remote update method");
123 return (yppasswd_remote(ypclnt, pwd, passwd));
125 YPCLNT_DEBUG("using local update method");
126 return (yppasswd_local(ypclnt, pwd));
128 YPCLNT_DEBUG("no rpc.yppasswdd");
134 * yppasswd_remote and yppasswd_local are quite similar but still
135 * sufficiently different that merging them into one makes the code
136 * significantly less readable, IMHO, so we keep them separate.
140 yppasswd_local(ypclnt_t *ypclnt, const struct passwd *pwd)
142 struct master_yppasswd yppwd;
143 struct rpc_err rpcerr;
144 struct netconfig *nc = NULL;
145 void *localhandle = 0;
149 /* fill the master_yppasswd structure */
150 memset(&yppwd, 0, sizeof yppwd);
151 yppwd.newpw.pw_uid = pwd->pw_uid;
152 yppwd.newpw.pw_gid = pwd->pw_gid;
153 yppwd.newpw.pw_change = pwd->pw_change;
154 yppwd.newpw.pw_expire = pwd->pw_expire;
155 yppwd.newpw.pw_fields = pwd->pw_fields;
156 yppwd.oldpass = strdup("");
157 yppwd.domain = strdup(ypclnt->domain);
158 if ((yppwd.newpw.pw_name = strdup(pwd->pw_name)) == NULL ||
159 (yppwd.newpw.pw_passwd = strdup(pwd->pw_passwd)) == NULL ||
160 (yppwd.newpw.pw_class = strdup(pwd->pw_class)) == NULL ||
161 (yppwd.newpw.pw_gecos = strdup(pwd->pw_gecos)) == NULL ||
162 (yppwd.newpw.pw_dir = strdup(pwd->pw_dir)) == NULL ||
163 (yppwd.newpw.pw_shell = strdup(pwd->pw_shell)) == NULL) {
164 ypclnt_error(ypclnt, __func__, strerror(errno));
169 /* connect to rpc.yppasswdd */
170 localhandle = setnetconfig();
171 while ((nc = getnetconfig(localhandle)) != NULL) {
172 if (nc->nc_protofmly != NULL &&
173 strcmp(nc->nc_protofmly, NC_LOOPBACK) == 0)
177 ypclnt_error(ypclnt, __func__,
178 "getnetconfig: %s", nc_sperror());
182 if ((clnt = clnt_tp_create(NULL, MASTER_YPPASSWDPROG,
183 MASTER_YPPASSWDVERS, nc)) == NULL) {
184 ypclnt_error(ypclnt, __func__,
185 "failed to connect to rpc.yppasswdd: %s",
186 clnt_spcreateerror(ypclnt->server));
190 clnt->cl_auth = authunix_create_default();
192 /* request the update */
193 result = yppasswdproc_update_master_1(&yppwd, clnt);
195 /* check for RPC errors */
196 clnt_geterr(clnt, &rpcerr);
197 if (rpcerr.re_status != RPC_SUCCESS) {
198 ypclnt_error(ypclnt, __func__,
199 "NIS password update failed: %s",
200 clnt_sperror(clnt, ypclnt->server));
205 /* check the result of the update */
206 if (result == NULL || *result != 0) {
207 ypclnt_error(ypclnt, __func__,
208 "NIS password update failed");
209 /* XXX how do we get more details? */
214 ypclnt_error(ypclnt, NULL, NULL);
219 auth_destroy(clnt->cl_auth);
222 endnetconfig(localhandle);
223 free(yppwd.newpw.pw_name);
224 if (yppwd.newpw.pw_passwd != NULL) {
225 memset(yppwd.newpw.pw_passwd, 0, strlen(yppwd.newpw.pw_passwd));
226 free(yppwd.newpw.pw_passwd);
228 free(yppwd.newpw.pw_class);
229 free(yppwd.newpw.pw_gecos);
230 free(yppwd.newpw.pw_dir);
231 free(yppwd.newpw.pw_shell);
232 if (yppwd.oldpass != NULL) {
233 memset(yppwd.oldpass, 0, strlen(yppwd.oldpass));
240 yppasswd_remote(ypclnt_t *ypclnt, const struct passwd *pwd, const char *passwd)
242 struct yppasswd yppwd;
243 struct rpc_err rpcerr;
247 /* fill the yppasswd structure */
248 memset(&yppwd, 0, sizeof yppwd);
249 yppwd.newpw.pw_uid = pwd->pw_uid;
250 yppwd.newpw.pw_gid = pwd->pw_gid;
251 if ((yppwd.newpw.pw_name = strdup(pwd->pw_name)) == NULL ||
252 (yppwd.newpw.pw_passwd = strdup(pwd->pw_passwd)) == NULL ||
253 (yppwd.newpw.pw_gecos = strdup(pwd->pw_gecos)) == NULL ||
254 (yppwd.newpw.pw_dir = strdup(pwd->pw_dir)) == NULL ||
255 (yppwd.newpw.pw_shell = strdup(pwd->pw_shell)) == NULL ||
256 (yppwd.oldpass = strdup(passwd ? passwd : "")) == NULL) {
257 ypclnt_error(ypclnt, __func__, strerror(errno));
262 /* connect to rpc.yppasswdd */
263 clnt = clnt_create(ypclnt->server, YPPASSWDPROG, YPPASSWDVERS, "udp");
265 ypclnt_error(ypclnt, __func__,
266 "failed to connect to rpc.yppasswdd: %s",
267 clnt_spcreateerror(ypclnt->server));
271 clnt->cl_auth = authunix_create_default();
273 /* request the update */
274 result = yppasswdproc_update_1(&yppwd, clnt);
276 /* check for RPC errors */
277 clnt_geterr(clnt, &rpcerr);
278 if (rpcerr.re_status != RPC_SUCCESS) {
279 ypclnt_error(ypclnt, __func__,
280 "NIS password update failed: %s",
281 clnt_sperror(clnt, ypclnt->server));
286 /* check the result of the update */
287 if (result == NULL || *result != 0) {
288 ypclnt_error(ypclnt, __func__,
289 "NIS password update failed");
290 /* XXX how do we get more details? */
295 ypclnt_error(ypclnt, NULL, NULL);
300 auth_destroy(clnt->cl_auth);
303 free(yppwd.newpw.pw_name);
304 if (yppwd.newpw.pw_passwd != NULL) {
305 memset(yppwd.newpw.pw_passwd, 0, strlen(yppwd.newpw.pw_passwd));
306 free(yppwd.newpw.pw_passwd);
308 free(yppwd.newpw.pw_gecos);
309 free(yppwd.newpw.pw_dir);
310 free(yppwd.newpw.pw_shell);
311 if (yppwd.oldpass != NULL) {
312 memset(yppwd.oldpass, 0, strlen(yppwd.oldpass));