diff options
Diffstat (limited to 'nis/nis_call.c')
-rw-r--r-- | nis/nis_call.c | 546 |
1 files changed, 349 insertions, 197 deletions
diff --git a/nis/nis_call.c b/nis/nis_call.c index 08a20ac..f25b801 100644 --- a/nis/nis_call.c +++ b/nis/nis_call.c @@ -17,6 +17,7 @@ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include <fcntl.h> #include <string.h> #include <rpc/rpc.h> #include <rpc/auth.h> @@ -26,8 +27,30 @@ #include <arpa/inet.h> #include "nis_intern.h" -static struct timeval TIMEOUT = {25, 0}; -static int const MAXTRIES = 3; +static struct timeval TIMEOUT = {10, 0}; + +struct dir_binding +{ + CLIENT *clnt; /* RPC CLIENT handle */ + nis_server *server_val; /* List of servers */ + u_int server_len; /* # of servers */ + u_int server_used; /* Which server we are bind in the moment ? */ + u_int trys; /* How many server have we tried ? */ + bool_t master_only; /* Is only binded to the master */ + bool_t use_auth; /* Do we use AUTH ? */ + bool_t use_udp; /* Do we use UDP ? */ + time_t create; /* Binding creation time */ + struct sockaddr_in addr; /* Server's IP address */ + int socket; /* Server's local socket */ + unsigned short port; /* Local port */ +}; +typedef struct dir_binding dir_binding; + +static inline u_int +__nis_ping (const nis_server *serv, u_int serv_len) +{ + return 0; +} static unsigned long inetstr2int (const char *str) @@ -53,110 +76,217 @@ inetstr2int (const char *str) return inet_addr (buffer); } -static CLIENT * -__nis_dobind (const nis_server *server, u_long flags) +static void +__bind_destroy (dir_binding *bind) { - struct sockaddr_in clnt_saddr; - int clnt_sock; - size_t i; - CLIENT *client = NULL; - - memset (&clnt_saddr, '\0', sizeof clnt_saddr); - clnt_saddr.sin_family = AF_INET; - for (i = 0; i < server->ep.ep_len; i++) + if (bind->clnt != NULL) { - if (strcmp (server->ep.ep_val[i].family, "loopback") == 0) + if (bind->use_auth) + auth_destroy (bind->clnt->cl_auth); + clnt_destroy (bind->clnt); + } + free (bind->server_val); + free (bind); +} + +static nis_error +__bind_next (dir_binding *bind) +{ + if (bind->trys >= bind->server_len) + return NIS_FAIL; + + bind->server_used++; + if (bind->server_used >= bind->server_len) + bind->server_used = 0; + + if (bind->clnt != NULL) + { + if (bind->use_auth) + auth_destroy (bind->clnt->cl_auth); + clnt_destroy (bind->clnt); + bind->clnt = NULL; + } + + return NIS_SUCCESS; +} + +static nis_error +__bind_connect (dir_binding *dbp) +{ + struct sockaddr_in check; + nis_server *serv; + int checklen; + u_int i; + + if (dbp == NULL) + return NIS_FAIL; + + serv = &dbp->server_val[dbp->server_used]; + + memset (&dbp->addr, '\0', sizeof (dbp->addr)); + dbp->addr.sin_family = AF_INET; + for (i = 0; i < serv->ep.ep_len; ++i) + { + if (strcmp (serv->ep.ep_val[i].family, "inet") == 0) { - if (server->ep.ep_val[i].uaddr[i] == '-') - clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + if (dbp->use_udp) + { + if (strcmp (serv->ep.ep_val[i].proto, "udp") == 0) + dbp->addr.sin_addr.s_addr = + inetstr2int (serv->ep.ep_val[i].uaddr); + else + continue; + } else - if (strcmp (server->ep.ep_val[i].proto, "udp") == 0) - { - if ((flags & USE_DGRAM) == USE_DGRAM) - clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); - else - continue; - } - else - if (strcmp (server->ep.ep_val[i].proto, "tcp") == 0) - { - if ((flags & USE_DGRAM) == USE_DGRAM) - continue; - else - clnt_saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); - } + if (strcmp (serv->ep.ep_val[i].proto, "tcp") == 0) + dbp->addr.sin_addr.s_addr = + inetstr2int (serv->ep.ep_val[i].uaddr); } else - if (strcmp (server->ep.ep_val[i].family, "inet") == 0) - { - if (server->ep.ep_val[i].uaddr[i] == '-') - clnt_saddr.sin_addr.s_addr = - inetstr2int (server->ep.ep_val[i].uaddr); - else - if (strcmp (server->ep.ep_val[i].proto, "udp") == 0) - { - if ((flags & USE_DGRAM) == USE_DGRAM) - clnt_saddr.sin_addr.s_addr = - inetstr2int (server->ep.ep_val[i].uaddr); - else - continue; - } - else - if (strcmp (server->ep.ep_val[i].proto, "tcp") == 0) - { - if ((flags & USE_DGRAM) == USE_DGRAM) - continue; - else - clnt_saddr.sin_addr.s_addr = - inetstr2int (server->ep.ep_val[i].uaddr); - } - } - else - continue; - - clnt_sock = RPC_ANYSOCK; - if ((flags & USE_DGRAM) == USE_DGRAM) - client = clntudp_create (&clnt_saddr, NIS_PROG, NIS_VERSION, - TIMEOUT, &clnt_sock); - else - client = clnttcp_create (&clnt_saddr, NIS_PROG, NIS_VERSION, - &clnt_sock, 0, 0); - - if (client == NULL) continue; - if (clnt_call (client, 0, (xdrproc_t) xdr_void, NULL, - (xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) + } + if (dbp->addr.sin_addr.s_addr == 0) + return NIS_FAIL; + + dbp->socket = RPC_ANYSOCK; + if (dbp->use_udp) + dbp->clnt = clntudp_create (&dbp->addr, NIS_PROG, NIS_VERSION, + TIMEOUT, &dbp->socket); + else + dbp->clnt = clnttcp_create (&dbp->addr, NIS_PROG, NIS_VERSION, + &dbp->socket, 0, 0); + + if (dbp->clnt == NULL) + return NIS_RPCERROR; + + clnt_control (dbp->clnt, CLSET_TIMEOUT, (caddr_t)&TIMEOUT); + /* If the program exists, close the socket */ + if (fcntl (dbp->socket, F_SETFD, 1) == -1) + perror (_("fcntl: F_SETFD")); + + if (dbp->use_auth) + { +#if defined(HAVE_SECURE_RPC) + if (serv->key_type == NIS_PK_DH) { - clnt_destroy (client); - continue; + char netname[MAXNETNAMELEN+1]; + char *p; + + p = stpcpy (netname, "unix."); + strncpy (p, serv->name,MAXNETNAMELEN-5); + netname[MAXNETNAMELEN] = '\0'; + p = strchr (netname, '.'); + *p = '@'; + dbp->clnt->cl_auth = + authdes_pk_create (netname, &serv->pkey, 300, NULL, NULL); + if (!dbp->clnt->cl_auth) + dbp->clnt->cl_auth = authunix_create_default (); } + else +#endif + dbp->clnt->cl_auth = authunix_create_default (); + dbp->use_auth = TRUE; + } + + /* Get port for sanity checks later */ + checklen = sizeof (struct sockaddr_in); + memset (&check, 0, checklen); + if (dbp->use_udp) + bind (dbp->socket, (struct sockaddr *)&check, checklen); + check.sin_family = AF_INET; + if (!getsockname (dbp->socket, (struct sockaddr *)&check, &checklen)) + dbp->port = check.sin_port; + + dbp->create = time (NULL); + + return NIS_SUCCESS; +} - if ((flags & NO_AUTHINFO) != NO_AUTHINFO) +static dir_binding * +__bind_create (const nis_server *serv_val, u_int serv_len, u_long flags) +{ + dir_binding *dbp; + u_int i; + + dbp = calloc (1, sizeof (dir_binding)); + if (dbp == NULL) + return NULL; + + dbp->server_len = serv_len; + dbp->server_val = calloc (1, sizeof (nis_server) * serv_len); + if (dbp->server_val == NULL) + { + free (dbp); + return NULL; + } + + for (i = 0; i < serv_len; ++i) + { + if (serv_val[i].name != NULL) + dbp->server_val[i].name = strdup (serv_val[i].name); + + dbp->server_val[i].ep.ep_len = serv_val[i].ep.ep_len; + if (dbp->server_val[i].ep.ep_len > 0) { -#if defined(HAVE_SECURE_RPC) - if (server->key_type == NIS_PK_DH && getenv ("NO_SECURE_RPC") == NULL) + unsigned long j; + + dbp->server_val[i].ep.ep_val = + malloc (serv_val[i].ep.ep_len * sizeof (endpoint)); + for (j = 0; j < dbp->server_val[i].ep.ep_len; ++j) { - char netname[MAXNETNAMELEN+1]; - char *p; - - p = stpcpy (netname, "unix."); - strncpy (p, server->name,MAXNETNAMELEN-5); - netname[MAXNETNAMELEN] = '\0'; - p = strchr (netname, '.'); - *p = '@'; - client->cl_auth = - authdes_pk_create (netname, &server->pkey, 300, NULL, NULL); - if (!client->cl_auth) - client->cl_auth = authunix_create_default (); + if (serv_val[i].ep.ep_val[j].uaddr) + dbp->server_val[i].ep.ep_val[j].uaddr = + strdup (serv_val[i].ep.ep_val[j].uaddr); + else + dbp->server_val[i].ep.ep_val[j].uaddr = NULL; + if (serv_val[i].ep.ep_val[j].family) + dbp->server_val[i].ep.ep_val[j].family = + strdup (serv_val[i].ep.ep_val[j].family); + else + dbp->server_val[i].ep.ep_val[j].family = NULL; + if (serv_val[i].ep.ep_val[j].proto) + dbp->server_val[i].ep.ep_val[j].proto = + strdup (serv_val[i].ep.ep_val[j].proto); + else + dbp->server_val[i].ep.ep_val[j].proto = NULL; } - else -#endif - client->cl_auth = authunix_create_default (); } - return client; + else + dbp->server_val[i].ep.ep_val = NULL; + dbp->server_val[i].key_type = serv_val[i].key_type; + dbp->server_val[i].pkey.n_len = serv_val[i].pkey.n_len; + if (serv_val[i].pkey.n_len > 0) + { + dbp->server_val[i].pkey.n_bytes = + malloc (serv_val[i].pkey.n_len); + if (dbp->server_val[i].pkey.n_bytes == NULL) + return NULL; + memcpy (dbp->server_val[i].pkey.n_bytes, serv_val[i].pkey.n_bytes, + serv_val[i].pkey.n_len); + } + else + dbp->server_val[i].pkey.n_bytes = NULL; } + + dbp->server_used = __nis_ping (dbp->server_val, dbp->server_len); + if (flags & USE_DGRAM) + dbp->use_udp = TRUE; + else + dbp->use_udp = FALSE; - return NULL; + if (flags & NO_AUTHINFO) + dbp->use_auth = FALSE; + else + dbp->use_auth = TRUE; + + if (flags & MASTER_ONLY) + dbp->master_only = TRUE; + else + dbp->master_only = FALSE; + + dbp->trys = 1; + + return dbp; } nis_error @@ -164,89 +294,84 @@ __do_niscall2 (const nis_server *server, u_int server_len, u_long prog, xdrproc_t xargs, caddr_t req, xdrproc_t xres, caddr_t resp, u_long flags) { - CLIENT *clnt; - int try, result; - - try = 0; - result = NIS_NAMEUNREACHABLE; - - if (((flags & MASTER_ONLY) == MASTER_ONLY) && server_len > 1) - server_len = 1; /* The first entry is the master */ - - while (try < MAXTRIES && result != RPC_SUCCESS) + enum clnt_stat result; + nis_error retcode; + dir_binding *dbp; + + if (flags & MASTER_ONLY) + server_len = 1; + + dbp = __bind_create (server, server_len, flags); + while (__bind_connect (dbp) != NIS_SUCCESS) { - unsigned int i; - - if ((flags & HARD_LOOKUP) == 0) - ++try; - - for (i = 0; i < server_len; i++) + if (__bind_next (dbp) != NIS_SUCCESS) { - if ((clnt = __nis_dobind (&server[i], flags)) == NULL) - continue; - - result = clnt_call (clnt, prog, xargs, req, xres, resp, TIMEOUT); - - if (result != RPC_SUCCESS) - { - clnt_perror (clnt, "do_niscall: clnt_call"); - clnt_destroy (clnt); - result = NIS_RPCERROR; - } - else - clnt_destroy (clnt); + __bind_destroy (dbp); + return NIS_NAMEUNREACHABLE; } } - return result; -} - -static directory_obj * -dir_lookup (const_nis_name name, nis_server *serv, u_long flags) -{ - CLIENT *clnt; - int try, result; - nis_result *res; - struct ns_request req; - directory_obj *dir; - - res = calloc (1, sizeof (nis_result)); - req.ns_name = (char *)name; - req.ns_object.ns_object_len = 0; - req.ns_object.ns_object_val = NULL; - try = 0; - result = NIS_NAMEUNREACHABLE; - - while (try < MAXTRIES && result != RPC_SUCCESS) + do { - if ((clnt = __nis_dobind (serv, flags)) == NULL) - continue; - - result = clnt_call (clnt, NIS_LOOKUP, (xdrproc_t) xdr_ns_request, - (caddr_t) &req, (xdrproc_t) xdr_nis_result, - (caddr_t) res, TIMEOUT); - + again: + result = clnt_call (dbp->clnt, prog, xargs, req, xres, resp, TIMEOUT); + if (result != RPC_SUCCESS) { - clnt_perror (clnt, "do_niscall: clnt_call"); - clnt_destroy (clnt); - result = NIS_RPCERROR; + clnt_perror (dbp->clnt, "__do_niscall2: clnt_call"); + __bind_destroy (dbp); + retcode = NIS_RPCERROR; } else - clnt_destroy (clnt); + { + switch (prog) + { + case NIS_LOOKUP: + case NIS_ADD: + case NIS_MODIFY: + case NIS_REMOVE: + case NIS_IBLIST: + case NIS_IBADD: + case NIS_IBMODIFY: + case NIS_IBREMOVE: + case NIS_IBFIRST: + case NIS_IBNEXT: + if ((((nis_result *)xres)->status != NIS_SUCCESS) && + (((nis_result *)xres)->status != NIS_S_SUCCESS)) + if (__bind_next (dbp) == NIS_SUCCESS) + goto again; + case NIS_FINDDIRECTORY: + if (((fd_result *)xres)->status != NIS_SUCCESS) + if (__bind_next (dbp) == NIS_SUCCESS) + goto again; + break; +#if 0 + case NIS_STATUS: /* nis_taglist */ + case NIS_SERVSTATE: + break; + case NIS_DUMPLOG: /* log_result */ + case NIS_DUMP: + break; + case NIS_CHECKPOINT: /* cp_result */ + break; +#endif + default: + break; + } + __bind_destroy (dbp); + retcode = NIS_SUCCESS; + } } - if (result != RPC_SUCCESS || res->status != NIS_SUCCESS) - return NULL; - - dir = nis_clone_directory (&res->objects.objects_val->DI_data, NULL); - nis_freeresult (res); - - return dir; + while ((flags & HARD_LOOKUP) && retcode == NIS_RPCERROR); + + return retcode; } static directory_obj * rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags) { + fd_result *fd_res; + XDR xdrs; char domain [strlen (name) + 3]; nis_domain_of_r (name, domain, sizeof (domain)); @@ -287,8 +412,20 @@ rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags) /* The root server of our domain is a replica of the parent domain ! (Now I understand why a root server must be a replica of the parent domain) */ - obj = dir_lookup (ndomain, dir->do_servers.do_servers_val, - flags); + fd_res = __nis_finddirectory (dir, ndomain); + if (fd_res->status != NIS_SUCCESS) + { + nis_free_directory (dir); + xdr_free((xdrproc_t)xdr_fd_result, (caddr_t)fd_res); + return NULL; + } + __cache_add (fd_res); + obj = calloc(1, sizeof(directory_obj)); + xdrmem_create(&xdrs, fd_res->dir_data.dir_data_val, + fd_res->dir_data.dir_data_len, XDR_DECODE); + xdr_directory_obj(&xdrs, obj); + xdr_destroy(&xdrs); + xdr_free((xdrproc_t)xdr_fd_result, (caddr_t)fd_res); if (obj != NULL) { /* We have found a NIS+ server serving ndomain, now @@ -303,15 +440,14 @@ rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags) return NULL; } } - break; + break; case LOWER_NAME: { directory_obj *obj; char leaf [strlen (name) + 3]; char ndomain [strlen (name) + 3]; - u_int i; char *cp; - + do { if (strlen (domain) == 0) @@ -327,21 +463,30 @@ rec_dirsearch (const_nis_name name, directory_obj *dir, u_long flags) cp = strchr (leaf, '\0'); *cp++ = '.'; strcpy (cp, domain); - - for (i = 0; i < dir->do_servers.do_servers_len; ++i) + + fd_res = __nis_finddirectory (dir, leaf); + if (fd_res->status != NIS_SUCCESS) { - obj = dir_lookup (leaf, &dir->do_servers.do_servers_val[i], - flags); - if (obj != NULL) - { - /* We have found a NIS+ server serving ndomain, now - let us search for "name" */ - nis_free_directory (dir); - return rec_dirsearch (name, obj, flags); - } + nis_free_directory (dir); + xdr_free((xdrproc_t)xdr_fd_result, (caddr_t)fd_res); + return NULL; + } + __cache_add (fd_res); + obj = calloc(1, sizeof(directory_obj)); + xdrmem_create(&xdrs, fd_res->dir_data.dir_data_val, + fd_res->dir_data.dir_data_len, XDR_DECODE); + xdr_directory_obj(&xdrs, obj); + xdr_destroy(&xdrs); + xdr_free((xdrproc_t)xdr_fd_result, (caddr_t)fd_res); + if (obj != NULL) + { + /* We have found a NIS+ server serving ndomain, now + let us search for "name" */ + nis_free_directory (dir); + return rec_dirsearch (name, obj, flags); } } - break; + break; case BAD_NAME: nis_free_directory (dir); return NULL; @@ -354,37 +499,44 @@ nis_error __do_niscall (const_nis_name name, u_long prog, xdrproc_t xargs, caddr_t req, xdrproc_t xres, caddr_t resp, u_long flags) { - nis_error result; + nis_error retcode; directory_obj *dir = NULL; - const nis_server *server; + nis_server *server; u_int server_len; + if (name == NULL) + return NIS_BADNAME; - dir = readColdStartFile (); - if (dir == NULL) /* No /var/nis/NIS_COLD_START -> no NIS+ installed */ - return NIS_UNAVAIL; - - if (name != NULL) + if ((flags & NO_CACHE) != NO_CACHE) + dir = __cache_search (name); + + if (dir == NULL) { + dir = readColdStartFile (); + if (dir == NULL) /* No /var/nis/NIS_COLD_START->no NIS+ installed */ + return NIS_UNAVAIL; + dir = rec_dirsearch (name, dir, flags); if (dir == NULL) - { - if (nis_dir_cmp (nis_local_directory(), name) == NOT_SEQUENTIAL) - return NIS_NAMEUNREACHABLE; - else - return NIS_NOTFOUND; - } + return NIS_NOTFOUND; } - server = dir->do_servers.do_servers_val; - server_len = dir->do_servers.do_servers_len; - if (((flags & MASTER_ONLY) == MASTER_ONLY) && server_len > 1) - server_len = 1; /* The first entry is the master */ - - result = __do_niscall2 (server, server_len, prog, xargs, req, xres, - resp, flags); - if (dir != NULL) - nis_free_directory (dir); + if (flags & MASTER_ONLY) + { + server = dir->do_servers.do_servers_val; + server_len = 1; + } + else + { + server = dir->do_servers.do_servers_val; + server_len = dir->do_servers.do_servers_len; + } + + + retcode = __do_niscall2 (server, server_len, prog, xargs, req, xres, resp, + flags); + + nis_free_directory (dir); - return result; + return retcode; } |