2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2002 Networks Associates Technology, Inc.
7 * This software was developed for the FreeBSD Project by ThinkSec AS and
8 * NAI Labs, the Security Research Division of Network Associates, Inc.
9 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
10 * DARPA CHATS research program.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. The name of the author may not be used to endorse or promote
21 * products derived from this software without specific prior written
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <netinet/in.h>
45 #include <netconfig.h>
52 #include <rpcsvc/ypclnt.h>
53 #include <rpcsvc/yppasswd.h>
56 #include "yppasswd_private.h"
58 static int yppasswd_remote(ypclnt_t *, const struct passwd *, const char *);
59 static int yppasswd_local(ypclnt_t *, const struct passwd *);
62 * Determines the availability of rpc.yppasswdd. Returns -1 for not
63 * available (or unable to determine), 0 for available, 1 for available in
67 ypclnt_havepasswdd(ypclnt_t *ypclnt)
69 struct netconfig *nc = NULL;
70 void *localhandle = NULL;
74 /* check if rpc.yppasswdd is running */
75 if (getrpcport(ypclnt->server, YPPASSWDPROG,
76 YPPASSWDPROC_UPDATE, IPPROTO_UDP) == 0) {
77 ypclnt_error(ypclnt, __func__, "no rpc.yppasswdd on server");
81 /* if we're not root, use remote method */
85 /* try to connect to rpc.yppasswdd */
86 localhandle = setnetconfig();
87 while ((nc = getnetconfig(localhandle)) != NULL) {
88 if (nc->nc_protofmly != NULL &&
89 strcmp(nc->nc_protofmly, NC_LOOPBACK) == 0)
93 ypclnt_error(ypclnt, __func__,
94 "getnetconfig: %s", nc_sperror());
98 if ((clnt = clnt_tp_create(NULL, MASTER_YPPASSWDPROG,
99 MASTER_YPPASSWDVERS, nc)) == NULL) {
100 ypclnt_error(ypclnt, __func__,
101 "failed to connect to rpc.yppasswdd: %s",
102 clnt_spcreateerror(ypclnt->server));
112 endnetconfig(localhandle);
117 * Updates the NIS user information for the specified user.
120 ypclnt_passwd(ypclnt_t *ypclnt, const struct passwd *pwd, const char *passwd)
122 switch (ypclnt_havepasswdd(ypclnt)) {
124 return (yppasswd_remote(ypclnt, pwd, passwd));
126 return (yppasswd_local(ypclnt, pwd));
133 * yppasswd_remote and yppasswd_local are quite similar but still
134 * sufficiently different that merging them into one makes the code
135 * significantly less readable, IMHO, so we keep them separate.
139 yppasswd_local(ypclnt_t *ypclnt, const struct passwd *pwd)
141 struct master_yppasswd yppwd;
142 struct rpc_err rpcerr;
143 struct netconfig *nc = NULL;
144 void *localhandle = NULL;
148 /* fill the master_yppasswd structure */
149 memset(&yppwd, 0, sizeof yppwd);
150 yppwd.newpw.pw_uid = pwd->pw_uid;
151 yppwd.newpw.pw_gid = pwd->pw_gid;
152 yppwd.newpw.pw_change = pwd->pw_change;
153 yppwd.newpw.pw_expire = pwd->pw_expire;
154 yppwd.newpw.pw_fields = pwd->pw_fields;
155 yppwd.oldpass = strdup("");
156 yppwd.domain = strdup(ypclnt->domain);
157 if ((yppwd.newpw.pw_name = strdup(pwd->pw_name)) == NULL ||
158 (yppwd.newpw.pw_passwd = strdup(pwd->pw_passwd)) == NULL ||
159 (yppwd.newpw.pw_class = strdup(pwd->pw_class)) == NULL ||
160 (yppwd.newpw.pw_gecos = strdup(pwd->pw_gecos)) == NULL ||
161 (yppwd.newpw.pw_dir = strdup(pwd->pw_dir)) == NULL ||
162 (yppwd.newpw.pw_shell = strdup(pwd->pw_shell)) == NULL) {
163 ypclnt_error(ypclnt, __func__, strerror(errno));
168 /* connect to rpc.yppasswdd */
169 localhandle = setnetconfig();
170 while ((nc = getnetconfig(localhandle)) != NULL) {
171 if (nc->nc_protofmly != NULL &&
172 strcmp(nc->nc_protofmly, NC_LOOPBACK) == 0)
176 ypclnt_error(ypclnt, __func__,
177 "getnetconfig: %s", nc_sperror());
181 if ((clnt = clnt_tp_create(NULL, MASTER_YPPASSWDPROG,
182 MASTER_YPPASSWDVERS, nc)) == NULL) {
183 ypclnt_error(ypclnt, __func__,
184 "failed to connect to rpc.yppasswdd: %s",
185 clnt_spcreateerror(ypclnt->server));
189 clnt->cl_auth = authunix_create_default();
191 /* request the update */
192 result = yppasswdproc_update_master_1(&yppwd, clnt);
194 /* check for RPC errors */
195 clnt_geterr(clnt, &rpcerr);
196 if (rpcerr.re_status != RPC_SUCCESS) {
197 ypclnt_error(ypclnt, __func__,
198 "NIS password update failed: %s",
199 clnt_sperror(clnt, ypclnt->server));
204 /* check the result of the update */
205 if (result == NULL || *result != 0) {
206 ypclnt_error(ypclnt, __func__,
207 "NIS password update failed");
208 /* XXX how do we get more details? */
213 ypclnt_error(ypclnt, NULL, NULL);
218 auth_destroy(clnt->cl_auth);
221 endnetconfig(localhandle);
222 free(yppwd.newpw.pw_name);
223 if (yppwd.newpw.pw_passwd != NULL) {
224 memset(yppwd.newpw.pw_passwd, 0, strlen(yppwd.newpw.pw_passwd));
225 free(yppwd.newpw.pw_passwd);
227 free(yppwd.newpw.pw_class);
228 free(yppwd.newpw.pw_gecos);
229 free(yppwd.newpw.pw_dir);
230 free(yppwd.newpw.pw_shell);
231 if (yppwd.oldpass != NULL) {
232 memset(yppwd.oldpass, 0, strlen(yppwd.oldpass));
239 yppasswd_remote(ypclnt_t *ypclnt, const struct passwd *pwd, const char *passwd)
241 struct yppasswd yppwd;
242 struct rpc_err rpcerr;
246 /* fill the yppasswd structure */
247 memset(&yppwd, 0, sizeof yppwd);
248 yppwd.newpw.pw_uid = pwd->pw_uid;
249 yppwd.newpw.pw_gid = pwd->pw_gid;
250 if ((yppwd.newpw.pw_name = strdup(pwd->pw_name)) == NULL ||
251 (yppwd.newpw.pw_passwd = strdup(pwd->pw_passwd)) == NULL ||
252 (yppwd.newpw.pw_gecos = strdup(pwd->pw_gecos)) == NULL ||
253 (yppwd.newpw.pw_dir = strdup(pwd->pw_dir)) == NULL ||
254 (yppwd.newpw.pw_shell = strdup(pwd->pw_shell)) == NULL ||
255 (yppwd.oldpass = strdup(passwd ? passwd : "")) == NULL) {
256 ypclnt_error(ypclnt, __func__, strerror(errno));
261 /* connect to rpc.yppasswdd */
262 clnt = clnt_create(ypclnt->server, YPPASSWDPROG, YPPASSWDVERS, "udp");
264 ypclnt_error(ypclnt, __func__,
265 "failed to connect to rpc.yppasswdd: %s",
266 clnt_spcreateerror(ypclnt->server));
270 clnt->cl_auth = authunix_create_default();
272 /* request the update */
273 result = yppasswdproc_update_1(&yppwd, clnt);
275 /* check for RPC errors */
276 clnt_geterr(clnt, &rpcerr);
277 if (rpcerr.re_status != RPC_SUCCESS) {
278 ypclnt_error(ypclnt, __func__,
279 "NIS password update failed: %s",
280 clnt_sperror(clnt, ypclnt->server));
285 /* check the result of the update */
286 if (result == NULL || *result != 0) {
287 ypclnt_error(ypclnt, __func__,
288 "NIS password update failed");
289 /* XXX how do we get more details? */
294 ypclnt_error(ypclnt, NULL, NULL);
299 auth_destroy(clnt->cl_auth);
302 free(yppwd.newpw.pw_name);
303 if (yppwd.newpw.pw_passwd != NULL) {
304 memset(yppwd.newpw.pw_passwd, 0, strlen(yppwd.newpw.pw_passwd));
305 free(yppwd.newpw.pw_passwd);
307 free(yppwd.newpw.pw_gecos);
308 free(yppwd.newpw.pw_dir);
309 free(yppwd.newpw.pw_shell);
310 if (yppwd.oldpass != NULL) {
311 memset(yppwd.oldpass, 0, strlen(yppwd.oldpass));