npd_clnt.c revision 7d1e83948cb684521e72cab96020be241508f449
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Contains all the client-side routines to communicate
* with the NIS+ passwd update deamon.
*
*/
#include <stdlib.h>
#include <syslog.h>
#include <string.h>
#include <shadow.h>
#include <rpc/des_crypt.h>
#include <mp.h>
#include <rpc/key_prot.h>
#include <rpcsvc/nispasswd.h>
#include <rpcsvc/nis_dhext.h>
#include <memory.h>
#include <unistd.h>
#define _NPD_PASSMAXLEN 16
des_block *, unsigned int, unsigned int,
des_block *);
npd_newpass *, unsigned int, unsigned int,
des_block *);
npd_newpass2 *, unsigned int, unsigned int,
des_block *);
/*
* Loop thru the NIS+ security cf entries until one DH(EXT) mech key is
* successfully extracted from the server DHEXT netobj. Copy the hex key
* string to newly allocated memory and return it's address in 'keybuf'.
* The caller must free this memory. Also, dup the key length and algtype
* "alias" string and return it's address in keystr (which the caller
* must also free on successful return).
*
* Policy: If no valid cf entries exist or if the entry is the "des" compat
* one, then try it and then end search.
*
* Returns TRUE on success and FALSE on failure.
*/
static bool_t
char **keybuf, /* out */
char **keystr) /* out */
{
char *hexkey; /* hex public key */
mechanism_t **mpp;
if (AUTH_DES_COMPAT_CHK(mp)) {
goto try_auth_des;
}
if (! VALID_MECH_ENTRY(mp))
continue;
== 0) {
continue; /* try next mech */
}
return (TRUE);
} else
continue;
}
return (FALSE);
} else {
/* no valid cf mech entries or AUTH_DES compat entry found */
return (FALSE);
}
return (TRUE);
}
}
return (FALSE);
}
/*
* given the domain return the client handle to the rpc.nispasswdd
* that I need to contact and the master_servers' publickey and the
* the key length and algtype "alias" string.
*
* returns TRUE on success and FALSE on failure.
*
* on successful return, caller must free the srv_pubkey buf and
* the keystr buf.
*/
char *domain;
char **srv_pubkey; /* buf to hold the pubkey; out */
{
char buf[NIS_MAXNAMELEN];
/* strlen("org_dir.") + null + "." = 10 */
return (FALSE);
/* can't find any of the servers that serve this domain */
/* something is very wrong ! */
"can't get a list of servers for %s domain",
domain);
return (FALSE);
}
/*
* copy a publickey
*/
switch (master_srv->key_type) {
case NIS_PK_DHEXT:
key_type)) {
"could not get a DHEXT public key for master server '%s'",
master_srv->name);
(void) nis_freeservlist(srvs);
return (FALSE);
}
break;
case NIS_PK_DH:
(void) nis_freeservlist(srvs);
return (FALSE);
}
break;
case NIS_PK_NONE:
default:
/* server does not have a D-H key-pair */
(void) nis_freeservlist(srvs);
return (FALSE);
}
/*
* now that we have the universal addr for the master server,
* lets create the client handle to rpc.nispasswdd.
* always use VC and attempt to create an authenticated handle.
* nis_make_rpchandle() will attempt to use auth_des first,
* if user does not have D-H keys, then it will try auth_sys.
* sendsz and recvsz are 0 ==> choose defaults.
*
* First try NISPASSWD_VERS2. If it fails, fallback to NISPASSWD_VERS
*/
for (vers = NISPASSWD_VERS2;
0, NULL, NIS_SVCNAME_NISPASSWD);
}
/* done with server list */
(void) nis_freeservlist(srvs);
/*
* error syslog'd by nis_make_rpchandle()
*/
return (FALSE);
}
return (TRUE);
}
/* Default timeout can be changed using clnt_control() */
/*
* initiate the passwd update request session by sending
* username, domainname, the generated public key and
* the callers' old passwd encrypted with the common DES key.
* if it succeeds, decrypt the identifier and randval sent in
* the response; otherwise return an appropriate error code.
*/
char *user; /* user name */
char *domain; /* domain */
char *oldpass; /* clear old password */
char *key_type; /* key len and alg type string */
uint32_t *ident; /* ID, returned on first attempt */
int *err; /* error code, returned */
{
int cryptstat;
int i;
*err = NPD_INVALIDARGS;
return (NPD_FAILED);
}
if (clnt_vers == NISPASSWD_VERS) {
/* encrypt the passwd with the common des key */
*err = NPD_BUFTOOSMALL;
return (NPD_FAILED);
}
xpass[i] = '\0';
(char *)xpass, _NPD_PASSMAXLEN,
else
(char *)&ivec);
if (DES_FAILED(cryptstat)) {
*err = NPD_ENCRYPTFAIL;
return (NPD_FAILED);
}
} else {
/* encrypt the passwd with the common des key */
*err = NPD_BUFTOOSMALL;
return (NPD_FAILED);
}
xpass2[i] = '\0';
(char *)xpass2, __NPD2_MAXPASSBYTES,
else
if (DES_FAILED(cryptstat)) {
*err = NPD_ENCRYPTFAIL;
return (NPD_FAILED);
}
}
if (clnt_vers == NISPASSWD_VERS) {
} else {
}
req_arg.ident = *ident; /* on re-tries ident is non-zero */
TIMEOUT) != RPC_SUCCESS) {
/* following msg is printed on stderr */
(void) clnt_perror(clnt,
"authenticate call to rpc.nispasswdd failed");
*err = NPD_SRVNOTRESP;
return (NPD_FAILED);
}
case NPD_SUCCESS:
case NPD_TRYAGAIN:
/*
* decrypt the ident & randval
*/
*err = NPD_DECRYPTFAIL;
return (NPD_FAILED);
}
case NPD_FAILED:
return (NPD_FAILED);
default:
/*
* should never reach this case !
*/
*err = NPD_SYSTEMERR;
return (NPD_FAILED);
}
/* NOTREACHED */
}
/*
* authenticated the caller, now send the identifier; and the
* new password and the random value encrypted with the common
* DES key. Send any other changed password information in the
* clear.
*/
int
uint32_t ident; /* ID */
char *newpass; /* clear new password */
char *gecos; /* gecos */
char *shell; /* shell */
int *err; /* error code, returned */
{
unsigned int tmp_xrval;
unsigned int tmp_npd_pad;
*err = NPD_INVALIDARGS;
return (NPD_FAILED);
}
if (clnt_vers == NISPASSWD_VERS) {
send_arg.ident = ident;
*err = NPD_ENCRYPTFAIL;
return (NPD_FAILED);
}
/* gecos */
/* shell */
TIMEOUT) != RPC_SUCCESS) {
/* printed to stderr */
(void) clnt_perror(clnt,
"update call to rpc.nispasswdd failed");
*err = NPD_SRVNOTRESP;
return (NPD_FAILED);
}
} else {
send_arg2.ident = ident;
deskey)) {
*err = NPD_ENCRYPTFAIL;
return (NPD_FAILED);
}
/* gecos */
/* shell */
TIMEOUT) != RPC_SUCCESS) {
/* printed to stderr */
(void) clnt_perror(clnt,
"update call to rpc.nispasswdd failed");
*err = NPD_SRVNOTRESP;
return (NPD_FAILED);
}
}
case NPD_SUCCESS:
return (NPD_SUCCESS);
case NPD_PARTIALSUCCESS:
*err = NPD_SYSTEMERR;
return (NPD_FAILED);
}
*errlst = (nispasswd_error *)
*err = NPD_SYSTEMERR;
return (NPD_FAILED);
}
p->next = (nispasswd_error *)
p = p->next;
} else
}
return (NPD_PARTIALSUCCESS);
case NPD_FAILED:
return (NPD_FAILED);
default:
/*
* should never reach this case !
*/
*err = NPD_SYSTEMERR;
return (NPD_FAILED);
}
}
void
{
nispasswd_error *p;
return;
}
}