ypclnt_passwd.c revision 116393
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 116393 2003-06-15 10:36:53Z mbr $ 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 *); 57116393Smbrstatic int yppasswd_local(ypclnt_t *, const struct passwd *); 5894577Sdes 5996198Sdes/* 6096198Sdes * Determines the availability of rpc.yppasswdd. Returns -1 for not 6196198Sdes * available (or unable to determine), 0 for available, 1 for available in 6296198Sdes * master mode. 6396198Sdes */ 6494575Sdesint 6596198Sdesypclnt_havepasswdd(ypclnt_t *ypclnt) 6694575Sdes{ 67116393Smbr struct netconfig *nc = NULL; 68116393Smbr void *localhandle = 0; 69116393Smbr CLIENT *clnt = NULL; 70116393Smbr int ret; 7194575Sdes 72116393Smbr /* check if rpc.yppasswdd is running */ 7394575Sdes if (getrpcport(ypclnt->server, YPPASSWDPROG, 7494575Sdes YPPASSWDPROC_UPDATE, IPPROTO_UDP) == 0) { 7594575Sdes ypclnt_error(ypclnt, __func__, "no rpc.yppasswdd on server"); 7694575Sdes return (-1); 7794575Sdes } 7894575Sdes 7994577Sdes /* if we're not root, use remote method */ 8094577Sdes if (getuid() != 0) 8196198Sdes return (0); 8294577Sdes 83116393Smbr /* try to connect to rpc.yppasswdd */ 84116393Smbr localhandle = setnetconfig(); 85116393Smbr while ((nc = getnetconfig(localhandle)) != NULL) { 86116393Smbr if (nc->nc_protofmly != NULL && 87116393Smbr strcmp(nc->nc_protofmly, NC_LOOPBACK) == 0) 88116393Smbr break; 8994577Sdes } 90116393Smbr if (nc == NULL) { 91116393Smbr ypclnt_error(ypclnt, __func__, 92116393Smbr "getnetconfig: %s", nc_sperror()); 93116393Smbr ret = 0; 94116393Smbr goto done; 9594577Sdes } 96116393Smbr if ((clnt = clnt_tp_create(NULL, MASTER_YPPASSWDPROG, 97116393Smbr MASTER_YPPASSWDVERS, nc)) == NULL) { 98116393Smbr ypclnt_error(ypclnt, __func__, 99116393Smbr "failed to connect to rpc.yppasswdd: %s", 100116393Smbr clnt_spcreateerror(ypclnt->server)); 101116393Smbr ret = 0; 102116393Smbr goto done; 103116393Smbr } else 104116393Smbr ret = 1; 105116393Smbr 106116393Smbrdone: 107116393Smbr if (clnt != NULL) { 108116393Smbr clnt_destroy(clnt); 109116393Smbr } 110116393Smbr endnetconfig(localhandle); 111116393Smbr return (ret); 11294577Sdes} 11394577Sdes 11494577Sdes/* 11596198Sdes * Updates the NIS user information for the specified user. 11696198Sdes */ 11796198Sdesint 11896198Sdesypclnt_passwd(ypclnt_t *ypclnt, const struct passwd *pwd, const char *passwd) 11996198Sdes{ 12096198Sdes switch (ypclnt_havepasswdd(ypclnt)) { 12196198Sdes case 0: 12296198Sdes YPCLNT_DEBUG("using remote update method"); 12396198Sdes return (yppasswd_remote(ypclnt, pwd, passwd)); 12496198Sdes case 1: 12596198Sdes YPCLNT_DEBUG("using local update method"); 126116393Smbr return (yppasswd_local(ypclnt, pwd)); 12796198Sdes default: 12896198Sdes YPCLNT_DEBUG("no rpc.yppasswdd"); 12996198Sdes return (-1); 13096198Sdes } 13196198Sdes} 13296198Sdes 13396198Sdes/* 13494577Sdes * yppasswd_remote and yppasswd_local are quite similar but still 13594577Sdes * sufficiently different that merging them into one makes the code 13694577Sdes * significantly less readable, IMHO, so we keep them separate. 13794577Sdes */ 13894577Sdes 13994577Sdesstatic int 140116393Smbryppasswd_local(ypclnt_t *ypclnt, const struct passwd *pwd) 14194577Sdes{ 14294577Sdes struct master_yppasswd yppwd; 14394577Sdes struct rpc_err rpcerr; 14494577Sdes struct netconfig *nc = NULL; 145116393Smbr void *localhandle = 0; 14694577Sdes CLIENT *clnt = NULL; 14794577Sdes int ret, *result; 14894577Sdes 14994577Sdes /* fill the master_yppasswd structure */ 15094577Sdes memset(&yppwd, 0, sizeof yppwd); 15194577Sdes yppwd.newpw.pw_uid = pwd->pw_uid; 15294577Sdes yppwd.newpw.pw_gid = pwd->pw_gid; 15394577Sdes yppwd.newpw.pw_change = pwd->pw_change; 15494577Sdes yppwd.newpw.pw_expire = pwd->pw_expire; 15594577Sdes yppwd.newpw.pw_fields = pwd->pw_fields; 156116393Smbr yppwd.oldpass = strdup(""); 157116393Smbr yppwd.domain = strdup(ypclnt->domain); 15894577Sdes if ((yppwd.newpw.pw_name = strdup(pwd->pw_name)) == NULL || 15994577Sdes (yppwd.newpw.pw_passwd = strdup(pwd->pw_passwd)) == NULL || 16094577Sdes (yppwd.newpw.pw_class = strdup(pwd->pw_class)) == NULL || 16194577Sdes (yppwd.newpw.pw_gecos = strdup(pwd->pw_gecos)) == NULL || 16294577Sdes (yppwd.newpw.pw_dir = strdup(pwd->pw_dir)) == NULL || 163116393Smbr (yppwd.newpw.pw_shell = strdup(pwd->pw_shell)) == NULL) { 16494577Sdes ypclnt_error(ypclnt, __func__, strerror(errno)); 16594577Sdes ret = -1; 16694577Sdes goto done; 16794577Sdes } 16894577Sdes 16994577Sdes /* connect to rpc.yppasswdd */ 170116393Smbr localhandle = setnetconfig(); 171116393Smbr while ((nc = getnetconfig(localhandle)) != NULL) { 172116393Smbr if (nc->nc_protofmly != NULL && 173116393Smbr strcmp(nc->nc_protofmly, NC_LOOPBACK) == 0) 174116393Smbr break; 175116393Smbr } 176116393Smbr if (nc == NULL) { 17794577Sdes ypclnt_error(ypclnt, __func__, 178116393Smbr "getnetconfig: %s", nc_sperror()); 179116393Smbr ret = -1; 180116393Smbr goto done; 181116393Smbr } 182116393Smbr if ((clnt = clnt_tp_create(NULL, MASTER_YPPASSWDPROG, 183116393Smbr MASTER_YPPASSWDVERS, nc)) == NULL) { 184116393Smbr ypclnt_error(ypclnt, __func__, 18594577Sdes "failed to connect to rpc.yppasswdd: %s", 18694577Sdes clnt_spcreateerror(ypclnt->server)); 18794577Sdes ret = -1; 18894577Sdes goto done; 18994577Sdes } 19094577Sdes clnt->cl_auth = authunix_create_default(); 19194577Sdes 19294577Sdes /* request the update */ 19394577Sdes result = yppasswdproc_update_master_1(&yppwd, clnt); 19494577Sdes 19594577Sdes /* check for RPC errors */ 19694577Sdes clnt_geterr(clnt, &rpcerr); 19794577Sdes if (rpcerr.re_status != RPC_SUCCESS) { 19894577Sdes ypclnt_error(ypclnt, __func__, 19994577Sdes "NIS password update failed: %s", 20094577Sdes clnt_sperror(clnt, ypclnt->server)); 20194577Sdes ret = -1; 20294577Sdes goto done; 20394577Sdes } 20494577Sdes 20594577Sdes /* check the result of the update */ 20694577Sdes if (result == NULL || *result != 0) { 20794577Sdes ypclnt_error(ypclnt, __func__, 20894577Sdes "NIS password update failed"); 20994577Sdes /* XXX how do we get more details? */ 21094577Sdes ret = -1; 21194577Sdes goto done; 21294577Sdes } 21394577Sdes 21494577Sdes ypclnt_error(ypclnt, NULL, NULL); 21594577Sdes ret = 0; 21694577Sdes 21794577Sdes done: 21894577Sdes if (clnt != NULL) { 21994577Sdes auth_destroy(clnt->cl_auth); 22094577Sdes clnt_destroy(clnt); 22194577Sdes } 222116393Smbr endnetconfig(localhandle); 22394577Sdes free(yppwd.newpw.pw_name); 22495588Sdes if (yppwd.newpw.pw_passwd != NULL) { 22595588Sdes memset(yppwd.newpw.pw_passwd, 0, strlen(yppwd.newpw.pw_passwd)); 22695588Sdes free(yppwd.newpw.pw_passwd); 22795588Sdes } 22894577Sdes free(yppwd.newpw.pw_class); 22994577Sdes free(yppwd.newpw.pw_gecos); 23094577Sdes free(yppwd.newpw.pw_dir); 23194577Sdes free(yppwd.newpw.pw_shell); 23294577Sdes if (yppwd.oldpass != NULL) { 23394577Sdes memset(yppwd.oldpass, 0, strlen(yppwd.oldpass)); 23494577Sdes free(yppwd.oldpass); 23594577Sdes } 23694577Sdes return (ret); 23794577Sdes} 23894577Sdes 23994577Sdesstatic int 24094577Sdesyppasswd_remote(ypclnt_t *ypclnt, const struct passwd *pwd, const char *passwd) 24194577Sdes{ 24294577Sdes struct yppasswd yppwd; 24394577Sdes struct rpc_err rpcerr; 24494577Sdes CLIENT *clnt = NULL; 24594577Sdes int ret, *result; 24694577Sdes 24794575Sdes /* fill the yppasswd structure */ 24894575Sdes memset(&yppwd, 0, sizeof yppwd); 24994575Sdes yppwd.newpw.pw_uid = pwd->pw_uid; 25094575Sdes yppwd.newpw.pw_gid = pwd->pw_gid; 25194575Sdes if ((yppwd.newpw.pw_name = strdup(pwd->pw_name)) == NULL || 25294575Sdes (yppwd.newpw.pw_passwd = strdup(pwd->pw_passwd)) == NULL || 25394575Sdes (yppwd.newpw.pw_gecos = strdup(pwd->pw_gecos)) == NULL || 25494575Sdes (yppwd.newpw.pw_dir = strdup(pwd->pw_dir)) == NULL || 25594575Sdes (yppwd.newpw.pw_shell = strdup(pwd->pw_shell)) == NULL || 25696198Sdes (yppwd.oldpass = strdup(passwd ? passwd : "")) == NULL) { 25794575Sdes ypclnt_error(ypclnt, __func__, strerror(errno)); 25894575Sdes ret = -1; 25994575Sdes goto done; 26094575Sdes } 26194575Sdes 26294575Sdes /* connect to rpc.yppasswdd */ 26394575Sdes clnt = clnt_create(ypclnt->server, YPPASSWDPROG, YPPASSWDVERS, "udp"); 26494575Sdes if (clnt == NULL) { 26594575Sdes ypclnt_error(ypclnt, __func__, 26694575Sdes "failed to connect to rpc.yppasswdd: %s", 26794575Sdes clnt_spcreateerror(ypclnt->server)); 26894575Sdes ret = -1; 26994575Sdes goto done; 27094575Sdes } 27194575Sdes clnt->cl_auth = authunix_create_default(); 27294575Sdes 27394575Sdes /* request the update */ 27494575Sdes result = yppasswdproc_update_1(&yppwd, clnt); 27594575Sdes 27694575Sdes /* check for RPC errors */ 27794575Sdes clnt_geterr(clnt, &rpcerr); 27894575Sdes if (rpcerr.re_status != RPC_SUCCESS) { 27994575Sdes ypclnt_error(ypclnt, __func__, 28094575Sdes "NIS password update failed: %s", 28194575Sdes clnt_sperror(clnt, ypclnt->server)); 28294575Sdes ret = -1; 28394575Sdes goto done; 28494575Sdes } 28594575Sdes 28694575Sdes /* check the result of the update */ 28794575Sdes if (result == NULL || *result != 0) { 28894575Sdes ypclnt_error(ypclnt, __func__, 28994575Sdes "NIS password update failed"); 29094575Sdes /* XXX how do we get more details? */ 29194575Sdes ret = -1; 29294575Sdes goto done; 29394575Sdes } 29494575Sdes 29594575Sdes ypclnt_error(ypclnt, NULL, NULL); 29694575Sdes ret = 0; 29794575Sdes 29894575Sdes done: 29994575Sdes if (clnt != NULL) { 30094575Sdes auth_destroy(clnt->cl_auth); 30194575Sdes clnt_destroy(clnt); 30294575Sdes } 30394575Sdes free(yppwd.newpw.pw_name); 30495588Sdes if (yppwd.newpw.pw_passwd != NULL) { 30595588Sdes memset(yppwd.newpw.pw_passwd, 0, strlen(yppwd.newpw.pw_passwd)); 30695588Sdes free(yppwd.newpw.pw_passwd); 30795588Sdes } 30894575Sdes free(yppwd.newpw.pw_gecos); 30994575Sdes free(yppwd.newpw.pw_dir); 31094575Sdes free(yppwd.newpw.pw_shell); 31194575Sdes if (yppwd.oldpass != NULL) { 31294575Sdes memset(yppwd.oldpass, 0, strlen(yppwd.oldpass)); 31394575Sdes free(yppwd.oldpass); 31494575Sdes } 31594575Sdes return (ret); 31694575Sdes} 317