ypclnt_passwd.c revision 94577
194575Sdes/*- 294575Sdes * Copyright (c) 2002 Networks Associates Technology, Inc. 394575Sdes * All rights reserved. 494575Sdes * 594575Sdes * This software was developed for the FreeBSD Project by ThinkSec AS and 694575Sdes * NAI Labs, the Security Research Division of Network Associates, Inc. 794575Sdes * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 894575Sdes * DARPA CHATS research program. 994575Sdes * 1094575Sdes * Redistribution and use in source and binary forms, with or without 1194575Sdes * modification, are permitted provided that the following conditions 1294575Sdes * are met: 1394575Sdes * 1. Redistributions of source code must retain the above copyright 1494575Sdes * notice, this list of conditions and the following disclaimer. 1594575Sdes * 2. Redistributions in binary form must reproduce the above copyright 1694575Sdes * notice, this list of conditions and the following disclaimer in the 1794575Sdes * documentation and/or other materials provided with the distribution. 1894575Sdes * 3. The name of the author may not be used to endorse or promote 1994575Sdes * products derived from this software without specific prior written 2094575Sdes * permission. 2194575Sdes * 2294575Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2394575Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2494575Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2594575Sdes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2694575Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2794575Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2894575Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2994575Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3094575Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3194575Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3294575Sdes * SUCH DAMAGE. 3394575Sdes * 3494575Sdes * $FreeBSD: head/lib/libypclnt/ypclnt_passwd.c 94577 2002-04-13 06:57:14Z des $ 3594575Sdes */ 3694575Sdes 3794577Sdes#include <sys/types.h> 3894577Sdes#include <sys/socket.h> 3994577Sdes#include <netinet/in.h> 4094577Sdes 4194575Sdes#include <err.h> 4294575Sdes#include <errno.h> 4394577Sdes#include <netconfig.h> 4494577Sdes#include <netdb.h> 4594575Sdes#include <pwd.h> 4694575Sdes#include <stdlib.h> 4794575Sdes#include <string.h> 4894577Sdes#include <unistd.h> 4994575Sdes 5094575Sdes#include <rpcsvc/ypclnt.h> 5194575Sdes#include <rpcsvc/yppasswd.h> 5294575Sdes 5394575Sdes#include "ypclnt.h" 5494577Sdes#include "yppasswd_private.h" 5594575Sdes 5694577Sdesstatic int yppasswd_remote(ypclnt_t *, const struct passwd *, const char *); 5794577Sdesstatic int yppasswd_local(ypclnt_t *, const struct passwd *, const char *); 5894577Sdes 5994575Sdesint 6094575Sdesypclnt_passwd(ypclnt_t *ypclnt, const struct passwd *pwd, const char *passwd) 6194575Sdes{ 6294577Sdes struct addrinfo hints, *res; 6394577Sdes int sd; 6494575Sdes 6594575Sdes /* check that rpc.yppasswdd is running */ 6694575Sdes if (getrpcport(ypclnt->server, YPPASSWDPROG, 6794575Sdes YPPASSWDPROC_UPDATE, IPPROTO_UDP) == 0) { 6894575Sdes ypclnt_error(ypclnt, __func__, "no rpc.yppasswdd on server"); 6994575Sdes return (-1); 7094575Sdes } 7194575Sdes 7294577Sdes /* if we're not root, use remote method */ 7394577Sdes if (getuid() != 0) 7494577Sdes goto remote; 7594577Sdes 7694577Sdes /* try to determine if we are the server */ 7794577Sdes memset(&hints, 0, sizeof(hints)); 7894577Sdes hints.ai_family = AF_UNSPEC; 7994577Sdes hints.ai_socktype = SOCK_STREAM; 8094577Sdes hints.ai_protocol = 0; 8194577Sdes if (getaddrinfo(ypclnt->server, NULL, &hints, &res) != 0) 8294577Sdes goto remote; 8394577Sdes sd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 8494577Sdes if (sd == -1) { 8594577Sdes freeaddrinfo(res); 8694577Sdes goto remote; 8794577Sdes } 8894577Sdes if (bind(sd, res->ai_addr, res->ai_addrlen) == -1) { 8994577Sdes close(sd); 9094577Sdes freeaddrinfo(res); 9194577Sdes goto remote; 9294577Sdes } 9394577Sdes freeaddrinfo(res); 9494577Sdes close(sd); 9594577Sdes YPCLNT_DEBUG("using local update method"); 9694577Sdes return (yppasswd_local(ypclnt, pwd, passwd)); 9794577Sdes remote: 9894577Sdes YPCLNT_DEBUG("using remote update method"); 9994577Sdes return (yppasswd_remote(ypclnt, pwd, passwd)); 10094577Sdes} 10194577Sdes 10294577Sdes/* 10394577Sdes * yppasswd_remote and yppasswd_local are quite similar but still 10494577Sdes * sufficiently different that merging them into one makes the code 10594577Sdes * significantly less readable, IMHO, so we keep them separate. 10694577Sdes */ 10794577Sdes 10894577Sdesstatic int 10994577Sdesyppasswd_local(ypclnt_t *ypclnt, const struct passwd *pwd, const char *passwd) 11094577Sdes{ 11194577Sdes struct master_yppasswd yppwd; 11294577Sdes struct rpc_err rpcerr; 11394577Sdes struct netconfig *nc = NULL; 11494577Sdes CLIENT *clnt = NULL; 11594577Sdes int ret, *result; 11694577Sdes 11794577Sdes /* fill the master_yppasswd structure */ 11894577Sdes memset(&yppwd, 0, sizeof yppwd); 11994577Sdes yppwd.newpw.pw_uid = pwd->pw_uid; 12094577Sdes yppwd.newpw.pw_gid = pwd->pw_gid; 12194577Sdes yppwd.newpw.pw_change = pwd->pw_change; 12294577Sdes yppwd.newpw.pw_expire = pwd->pw_expire; 12394577Sdes yppwd.newpw.pw_fields = pwd->pw_fields; 12494577Sdes if ((yppwd.newpw.pw_name = strdup(pwd->pw_name)) == NULL || 12594577Sdes (yppwd.newpw.pw_passwd = strdup(pwd->pw_passwd)) == NULL || 12694577Sdes (yppwd.newpw.pw_class = strdup(pwd->pw_class)) == NULL || 12794577Sdes (yppwd.newpw.pw_gecos = strdup(pwd->pw_gecos)) == NULL || 12894577Sdes (yppwd.newpw.pw_dir = strdup(pwd->pw_dir)) == NULL || 12994577Sdes (yppwd.newpw.pw_shell = strdup(pwd->pw_shell)) == NULL || 13094577Sdes (yppwd.oldpass = strdup(passwd)) == NULL) { 13194577Sdes ypclnt_error(ypclnt, __func__, strerror(errno)); 13294577Sdes ret = -1; 13394577Sdes goto done; 13494577Sdes } 13594577Sdes 13694577Sdes /* connect to rpc.yppasswdd */ 13794577Sdes nc = getnetconfigent("unix"); 13894577Sdes clnt = clnt_tp_create(ypclnt->server, YPPASSWDPROG, YPPASSWDVERS, nc); 13994577Sdes if (clnt == NULL) { 14094577Sdes ypclnt_error(ypclnt, __func__, 14194577Sdes "failed to connect to rpc.yppasswdd: %s", 14294577Sdes clnt_spcreateerror(ypclnt->server)); 14394577Sdes ret = -1; 14494577Sdes goto done; 14594577Sdes } 14694577Sdes clnt->cl_auth = authunix_create_default(); 14794577Sdes 14894577Sdes /* request the update */ 14994577Sdes result = yppasswdproc_update_master_1(&yppwd, clnt); 15094577Sdes 15194577Sdes /* check for RPC errors */ 15294577Sdes clnt_geterr(clnt, &rpcerr); 15394577Sdes if (rpcerr.re_status != RPC_SUCCESS) { 15494577Sdes ypclnt_error(ypclnt, __func__, 15594577Sdes "NIS password update failed: %s", 15694577Sdes clnt_sperror(clnt, ypclnt->server)); 15794577Sdes ret = -1; 15894577Sdes goto done; 15994577Sdes } 16094577Sdes 16194577Sdes /* check the result of the update */ 16294577Sdes if (result == NULL || *result != 0) { 16394577Sdes ypclnt_error(ypclnt, __func__, 16494577Sdes "NIS password update failed"); 16594577Sdes /* XXX how do we get more details? */ 16694577Sdes ret = -1; 16794577Sdes goto done; 16894577Sdes } 16994577Sdes 17094577Sdes ypclnt_error(ypclnt, NULL, NULL); 17194577Sdes ret = 0; 17294577Sdes 17394577Sdes done: 17494577Sdes if (clnt != NULL) { 17594577Sdes auth_destroy(clnt->cl_auth); 17694577Sdes clnt_destroy(clnt); 17794577Sdes } 17894577Sdes if (nc != NULL) 17994577Sdes freenetconfigent(nc); 18094577Sdes free(yppwd.newpw.pw_name); 18194577Sdes free(yppwd.newpw.pw_passwd); 18294577Sdes free(yppwd.newpw.pw_class); 18394577Sdes free(yppwd.newpw.pw_gecos); 18494577Sdes free(yppwd.newpw.pw_dir); 18594577Sdes free(yppwd.newpw.pw_shell); 18694577Sdes if (yppwd.oldpass != NULL) { 18794577Sdes memset(yppwd.oldpass, 0, strlen(yppwd.oldpass)); 18894577Sdes free(yppwd.oldpass); 18994577Sdes } 19094577Sdes return (ret); 19194577Sdes} 19294577Sdes 19394577Sdesstatic int 19494577Sdesyppasswd_remote(ypclnt_t *ypclnt, const struct passwd *pwd, const char *passwd) 19594577Sdes{ 19694577Sdes struct yppasswd yppwd; 19794577Sdes struct rpc_err rpcerr; 19894577Sdes CLIENT *clnt = NULL; 19994577Sdes int ret, *result; 20094577Sdes 20194575Sdes /* fill the yppasswd structure */ 20294575Sdes memset(&yppwd, 0, sizeof yppwd); 20394575Sdes yppwd.newpw.pw_uid = pwd->pw_uid; 20494575Sdes yppwd.newpw.pw_gid = pwd->pw_gid; 20594575Sdes if ((yppwd.newpw.pw_name = strdup(pwd->pw_name)) == NULL || 20694575Sdes (yppwd.newpw.pw_passwd = strdup(pwd->pw_passwd)) == NULL || 20794575Sdes (yppwd.newpw.pw_gecos = strdup(pwd->pw_gecos)) == NULL || 20894575Sdes (yppwd.newpw.pw_dir = strdup(pwd->pw_dir)) == NULL || 20994575Sdes (yppwd.newpw.pw_shell = strdup(pwd->pw_shell)) == NULL || 21094575Sdes (yppwd.oldpass = strdup(passwd)) == NULL) { 21194575Sdes ypclnt_error(ypclnt, __func__, strerror(errno)); 21294575Sdes ret = -1; 21394575Sdes goto done; 21494575Sdes } 21594575Sdes 21694575Sdes /* connect to rpc.yppasswdd */ 21794575Sdes clnt = clnt_create(ypclnt->server, YPPASSWDPROG, YPPASSWDVERS, "udp"); 21894575Sdes if (clnt == NULL) { 21994575Sdes ypclnt_error(ypclnt, __func__, 22094575Sdes "failed to connect to rpc.yppasswdd: %s", 22194575Sdes clnt_spcreateerror(ypclnt->server)); 22294575Sdes ret = -1; 22394575Sdes goto done; 22494575Sdes } 22594575Sdes clnt->cl_auth = authunix_create_default(); 22694575Sdes 22794575Sdes /* request the update */ 22894575Sdes result = yppasswdproc_update_1(&yppwd, clnt); 22994575Sdes 23094575Sdes /* check for RPC errors */ 23194575Sdes clnt_geterr(clnt, &rpcerr); 23294575Sdes if (rpcerr.re_status != RPC_SUCCESS) { 23394575Sdes ypclnt_error(ypclnt, __func__, 23494575Sdes "NIS password update failed: %s", 23594575Sdes clnt_sperror(clnt, ypclnt->server)); 23694575Sdes ret = -1; 23794575Sdes goto done; 23894575Sdes } 23994575Sdes 24094575Sdes /* check the result of the update */ 24194575Sdes if (result == NULL || *result != 0) { 24294575Sdes ypclnt_error(ypclnt, __func__, 24394575Sdes "NIS password update failed"); 24494575Sdes /* XXX how do we get more details? */ 24594575Sdes ret = -1; 24694575Sdes goto done; 24794575Sdes } 24894575Sdes 24994575Sdes ypclnt_error(ypclnt, NULL, NULL); 25094575Sdes ret = 0; 25194575Sdes 25294575Sdes done: 25394575Sdes if (clnt != NULL) { 25494575Sdes auth_destroy(clnt->cl_auth); 25594575Sdes clnt_destroy(clnt); 25694575Sdes } 25794575Sdes free(yppwd.newpw.pw_name); 25894575Sdes free(yppwd.newpw.pw_passwd); 25994575Sdes free(yppwd.newpw.pw_gecos); 26094575Sdes free(yppwd.newpw.pw_dir); 26194575Sdes free(yppwd.newpw.pw_shell); 26294575Sdes if (yppwd.oldpass != NULL) { 26394575Sdes memset(yppwd.oldpass, 0, strlen(yppwd.oldpass)); 26494575Sdes free(yppwd.oldpass); 26594575Sdes } 26694575Sdes return (ret); 26794575Sdes} 268