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
34 * $FreeBSD: src/lib/libypclnt/ypclnt_passwd.c,v 1.7 2006/07/28 21:34:37 stefanf Exp $
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 return (yppasswd_remote(ypclnt
, pwd
, passwd
));
124 return (yppasswd_local(ypclnt
, pwd
));
131 * yppasswd_remote and yppasswd_local are quite similar but still
132 * sufficiently different that merging them into one makes the code
133 * significantly less readable, IMHO, so we keep them separate.
137 yppasswd_local(ypclnt_t
*ypclnt
, const struct passwd
*pwd
)
139 struct master_yppasswd yppwd
;
140 struct rpc_err rpcerr
;
141 struct netconfig
*nc
= NULL
;
142 void *localhandle
= 0;
146 /* fill the master_yppasswd structure */
147 memset(&yppwd
, 0, sizeof yppwd
);
148 yppwd
.newpw
.pw_uid
= pwd
->pw_uid
;
149 yppwd
.newpw
.pw_gid
= pwd
->pw_gid
;
150 yppwd
.newpw
.pw_change
= pwd
->pw_change
;
151 yppwd
.newpw
.pw_expire
= pwd
->pw_expire
;
152 yppwd
.newpw
.pw_fields
= pwd
->pw_fields
;
153 yppwd
.oldpass
= strdup("");
154 yppwd
.domain
= strdup(ypclnt
->domain
);
155 if ((yppwd
.newpw
.pw_name
= strdup(pwd
->pw_name
)) == NULL
||
156 (yppwd
.newpw
.pw_passwd
= strdup(pwd
->pw_passwd
)) == NULL
||
157 (yppwd
.newpw
.pw_class
= strdup(pwd
->pw_class
)) == NULL
||
158 (yppwd
.newpw
.pw_gecos
= strdup(pwd
->pw_gecos
)) == NULL
||
159 (yppwd
.newpw
.pw_dir
= strdup(pwd
->pw_dir
)) == NULL
||
160 (yppwd
.newpw
.pw_shell
= strdup(pwd
->pw_shell
)) == NULL
) {
161 ypclnt_error(ypclnt
, __func__
, strerror(errno
));
166 /* connect to rpc.yppasswdd */
167 localhandle
= setnetconfig();
168 while ((nc
= getnetconfig(localhandle
)) != NULL
) {
169 if (nc
->nc_protofmly
!= NULL
&&
170 strcmp(nc
->nc_protofmly
, NC_LOOPBACK
) == 0)
174 ypclnt_error(ypclnt
, __func__
,
175 "getnetconfig: %s", nc_sperror());
179 if ((clnt
= clnt_tp_create(NULL
, MASTER_YPPASSWDPROG
,
180 MASTER_YPPASSWDVERS
, nc
)) == NULL
) {
181 ypclnt_error(ypclnt
, __func__
,
182 "failed to connect to rpc.yppasswdd: %s",
183 clnt_spcreateerror(ypclnt
->server
));
187 clnt
->cl_auth
= authunix_create_default();
189 /* request the update */
190 result
= yppasswdproc_update_master_1(&yppwd
, clnt
);
192 /* check for RPC errors */
193 clnt_geterr(clnt
, &rpcerr
);
194 if (rpcerr
.re_status
!= RPC_SUCCESS
) {
195 ypclnt_error(ypclnt
, __func__
,
196 "NIS password update failed: %s",
197 clnt_sperror(clnt
, ypclnt
->server
));
202 /* check the result of the update */
203 if (result
== NULL
|| *result
!= 0) {
204 ypclnt_error(ypclnt
, __func__
,
205 "NIS password update failed");
206 /* XXX how do we get more details? */
211 ypclnt_error(ypclnt
, NULL
, NULL
);
216 auth_destroy(clnt
->cl_auth
);
219 endnetconfig(localhandle
);
220 free(yppwd
.newpw
.pw_name
);
221 if (yppwd
.newpw
.pw_passwd
!= NULL
) {
222 memset(yppwd
.newpw
.pw_passwd
, 0, strlen(yppwd
.newpw
.pw_passwd
));
223 free(yppwd
.newpw
.pw_passwd
);
225 free(yppwd
.newpw
.pw_class
);
226 free(yppwd
.newpw
.pw_gecos
);
227 free(yppwd
.newpw
.pw_dir
);
228 free(yppwd
.newpw
.pw_shell
);
229 if (yppwd
.oldpass
!= NULL
) {
230 memset(yppwd
.oldpass
, 0, strlen(yppwd
.oldpass
));
237 yppasswd_remote(ypclnt_t
*ypclnt
, const struct passwd
*pwd
, const char *passwd
)
239 struct yppasswd yppwd
;
240 struct rpc_err rpcerr
;
244 /* fill the yppasswd structure */
245 memset(&yppwd
, 0, sizeof yppwd
);
246 yppwd
.newpw
.pw_uid
= pwd
->pw_uid
;
247 yppwd
.newpw
.pw_gid
= pwd
->pw_gid
;
248 if ((yppwd
.newpw
.pw_name
= strdup(pwd
->pw_name
)) == NULL
||
249 (yppwd
.newpw
.pw_passwd
= strdup(pwd
->pw_passwd
)) == NULL
||
250 (yppwd
.newpw
.pw_gecos
= strdup(pwd
->pw_gecos
)) == NULL
||
251 (yppwd
.newpw
.pw_dir
= strdup(pwd
->pw_dir
)) == NULL
||
252 (yppwd
.newpw
.pw_shell
= strdup(pwd
->pw_shell
)) == NULL
||
253 (yppwd
.oldpass
= strdup(passwd
? passwd
: "")) == NULL
) {
254 ypclnt_error(ypclnt
, __func__
, strerror(errno
));
259 /* connect to rpc.yppasswdd */
260 clnt
= clnt_create(ypclnt
->server
, YPPASSWDPROG
, YPPASSWDVERS
, "udp");
262 ypclnt_error(ypclnt
, __func__
,
263 "failed to connect to rpc.yppasswdd: %s",
264 clnt_spcreateerror(ypclnt
->server
));
268 clnt
->cl_auth
= authunix_create_default();
270 /* request the update */
271 result
= yppasswdproc_update_1(&yppwd
, clnt
);
273 /* check for RPC errors */
274 clnt_geterr(clnt
, &rpcerr
);
275 if (rpcerr
.re_status
!= RPC_SUCCESS
) {
276 ypclnt_error(ypclnt
, __func__
,
277 "NIS password update failed: %s",
278 clnt_sperror(clnt
, ypclnt
->server
));
283 /* check the result of the update */
284 if (result
== NULL
|| *result
!= 0) {
285 ypclnt_error(ypclnt
, __func__
,
286 "NIS password update failed");
287 /* XXX how do we get more details? */
292 ypclnt_error(ypclnt
, NULL
, NULL
);
297 auth_destroy(clnt
->cl_auth
);
300 free(yppwd
.newpw
.pw_name
);
301 if (yppwd
.newpw
.pw_passwd
!= NULL
) {
302 memset(yppwd
.newpw
.pw_passwd
, 0, strlen(yppwd
.newpw
.pw_passwd
));
303 free(yppwd
.newpw
.pw_passwd
);
305 free(yppwd
.newpw
.pw_gecos
);
306 free(yppwd
.newpw
.pw_dir
);
307 free(yppwd
.newpw
.pw_shell
);
308 if (yppwd
.oldpass
!= NULL
) {
309 memset(yppwd
.oldpass
, 0, strlen(yppwd
.oldpass
));