/* * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights * Reserved. This file contains Original Code and/or Modifications of * Original Code as defined in and that are subject to the Apple Public * Source License Version 1.0 (the 'License'). You may not use this file * except in compliance with the License. Please obtain a copy of the * License at http://www.apple.com/publicsource and read it before using * this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the * License for the specific language governing rights and limitations * under the License." * * @APPLE_LICENSE_HEADER_END@ */ /* * NetInfo clone sanity check * Copyright 1994, NeXT Computer Inc. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ni_globals.h" #include "getstuff.h" #include "sanitycheck.h" #include #define READALL_TIMEOUT 60 ni_status checkserves(unsigned long, ni_name, unsigned long, ni_name); extern unsigned long sys_address(); void sanitycheck(ni_name mytag) { ni_name master, mastertag; unsigned long masteraddr; interface_list_t *l; int i; if (!getmaster(db_ni, &master, &mastertag)) { /* no master! */ system_log(LOG_ERR, "tag %s: can't determine master's host name", mytag); return; } masteraddr = getaddress(db_ni, master); if (masteraddr == 0) { /* no address for master */ system_log(LOG_ERR, "tag %s: can't determine master's address", mytag); return; } l = sys_interfaces(); if (l == NULL) return; for (i = 0; i < l->count; i++) { if ((l->interface[i].flags & IFF_UP) == 0) continue; if (l->interface[i].flags & IFF_LOOPBACK) continue; checkserves(masteraddr, mastertag, l->interface[i].addr.s_addr, mytag); } sys_interfaces_release(l); } ni_status checkserves(unsigned long masteraddr, ni_name mastertag, unsigned long myaddr, ni_name mytag) { struct sockaddr_in mastersin; struct in_addr myinaddr; char myserves[MAXPATHLEN + 16]; ni_index where; int status; int sock; CLIENT *cl; struct timeval tv; nibind_getregister_res res; ni_id_res id_res; ni_lookup_res lu_res; ni_lookup_args childdir; ni_namelist_res prop_res; ni_prop_args pa; mastersin.sin_addr.s_addr = masteraddr; mastersin.sin_port = 0; mastersin.sin_family = AF_INET; myinaddr.s_addr = myaddr; /* connect to master hosts's nibindd */ sock = socket_connect(&mastersin, NIBIND_PROG, NIBIND_VERS); if (sock < 0) { system_log(LOG_WARNING, "sanitycheck can't connect to %s/%s - %m", inet_ntoa(mastersin.sin_addr), mastertag); return NI_FAILED; } FD_SET(sock, &clnt_fdset); /* protect client socket */ cl = clnttcp_create(&mastersin, NIBIND_PROG, NIBIND_VERS, &sock, 0, 0); if (cl == NULL) { socket_close(sock); FD_CLR(sock, &clnt_fdset); /* unprotect client socket */ return NI_FAILED; } tv.tv_sec = READALL_TIMEOUT; tv.tv_usec = 0; /* get the ports for master's tag */ bzero((char *)&res, sizeof(res)); if (clnt_call(cl, NIBIND_GETREGISTER, xdr_ni_name, &mastertag, xdr_nibind_getregister_res, &res, tv) != RPC_SUCCESS) { /* call failed */ socket_lock(); clnt_destroy(cl); (void)close(sock); socket_unlock(); FD_CLR(sock, &clnt_fdset); /* unprotect client socket */ return NI_FAILED; } socket_lock(); clnt_destroy(cl); (void)close(sock); socket_unlock(); FD_CLR(sock, &clnt_fdset); /* unprotect client socket */ if (res.status != NI_OK) { /* no server for the master's tag */ system_log(LOG_ERR, "tag %s: master's tag %s is not served at master's addresss", mytag, mastertag); return res.status; } /* connect to the master */ mastersin.sin_port = htons(res.nibind_getregister_res_u.addrs.tcp_port); xdr_free(xdr_nibind_getregister_res, (void *)&res); sock = socket_connect(&mastersin, NI_PROG, NI_VERS); if (sock < 0) { system_log(LOG_WARNING, "sanitycheck can't connect to " "%s/%s - %m", inet_ntoa(mastersin.sin_addr), mastertag); return NI_FAILED; } FD_SET(sock, &clnt_fdset); /* protect client socket */ cl = clnttcp_create(&mastersin, NI_PROG, NI_VERS, &sock, 0, 0); if (cl == NULL) { /* can't connect to master */ socket_close(sock); FD_CLR(sock, &clnt_fdset); /* unprotect client socket */ return NI_FAILED; } FD_SET(sock, &clnt_fdset); /* protect client socket */ /* get root directory */ bzero((char *)&id_res, sizeof(id_res)); status = clnt_call(cl, _NI_ROOT, xdr_void, NULL, xdr_ni_id_res, &id_res, tv); if (status != NI_OK) { /* can't get root! */ socket_lock(); clnt_destroy(cl); (void)close(sock); socket_unlock(); FD_CLR(sock, &clnt_fdset); /* unprotect client socket */ system_log(LOG_ERR, "tag %s: can't get master's root directory", mytag); return status; } if (id_res.status != NI_OK) { /* can't get root! */ socket_lock(); clnt_destroy(cl); (void)close(sock); socket_unlock(); FD_CLR(sock, &clnt_fdset); /* unprotect client socket */ system_log(LOG_ERR, "tag %s: master has no root directory", mytag); return status; } childdir.key = malloc(16); childdir.value = malloc(16); /* get machines subdirectory */ childdir.id = id_res.ni_id_res_u.id; xdr_free(xdr_ni_id_res, (void *)&id_res); strcpy(childdir.key,"name"); strcpy(childdir.value,"machines"); bzero((char *)&lu_res, sizeof(lu_res)); status = clnt_call(cl, _NI_LOOKUP, xdr_ni_lookup_args, &childdir, xdr_ni_lookup_res, &lu_res, tv); if (status != NI_OK) { /* can't get /machines! */ free(childdir.key); free(childdir.value); socket_lock(); clnt_destroy(cl); (void)close(sock); socket_unlock(); FD_CLR(sock, &clnt_fdset); /* unprotect client socket */ system_log(LOG_ERR, "tag %s: can't get master's /machines directory", mytag); return status; } if (lu_res.status != NI_OK) { /* no /machines! */ free(childdir.key); free(childdir.value); socket_lock(); clnt_destroy(cl); (void)close(sock); socket_unlock(); FD_CLR(sock, &clnt_fdset); /* unprotect client socket */ system_log(LOG_ERR, "tag %s: can't get master's /machines directory", mytag); return lu_res.status; } if (lu_res.ni_lookup_res_u.stuff.idlist.ni_idlist_len == 0) { /* no /machines! */ xdr_free(xdr_ni_lookup_res, (void *)&lu_res); free(childdir.key); free(childdir.value); socket_lock(); clnt_destroy(cl); (void)close(sock); socket_unlock(); FD_CLR(sock, &clnt_fdset); /* unprotect client socket */ system_log(LOG_ERR, "tag %s: master has no /machines directory", mytag); return NI_NODIR; } /* get my subdirectory */ childdir.id.nii_object = lu_res.ni_lookup_res_u.stuff.idlist.ni_idlist_val[0]; xdr_free(xdr_ni_lookup_res, (void *)&lu_res); strcpy(childdir.key,"ip_address"); strcpy(childdir.value,(char *)inet_ntoa(myinaddr)); bzero((char *)&lu_res, sizeof(lu_res)); status = clnt_call(cl, _NI_LOOKUP, xdr_ni_lookup_args, &childdir, xdr_ni_lookup_res, &lu_res, tv); if (status != NI_OK) { /* can't get /machines/ip_address=! */ free(childdir.key); free(childdir.value); socket_lock(); clnt_destroy(cl); (void)close(sock); socket_unlock(); FD_CLR(sock, &clnt_fdset); /* unprotect client socket */ system_log(LOG_ERR, "tag %s: can't get master's /machines/ip_address=%s directory", mytag,(char *)inet_ntoa(myinaddr)); return status; } if (lu_res.status != NI_OK) { /* no /machines! */ free(childdir.key); free(childdir.value); socket_lock(); clnt_destroy(cl); (void)close(sock); socket_unlock(); FD_CLR(sock, &clnt_fdset); /* unprotect client socket */ system_log(LOG_ERR, "tag %s: can't get master's /machines/ip_address=%s directory", mytag,(char *)inet_ntoa(myinaddr)); return lu_res.status; } if (lu_res.ni_lookup_res_u.stuff.idlist.ni_idlist_len == 0) { /* can't get /machines/ip_address=! */ xdr_free(xdr_ni_lookup_res, (void *)&lu_res); free(childdir.key); free(childdir.value); socket_lock(); clnt_destroy(cl); (void)close(sock); socket_unlock(); FD_CLR(sock, &clnt_fdset); /* unprotect client socket */ system_log(LOG_ERR, "tag %s: master has no /machines/ip_address=%s directory", mytag,(char *)inet_ntoa(myinaddr)); return NI_NODIR; } /* list properties */ prop_res.ni_namelist_res_u.stuff.values.ni_namelist_val = NULL; childdir.id.nii_object = lu_res.ni_lookup_res_u.stuff.idlist.ni_idlist_val[0]; xdr_free(xdr_ni_lookup_res, (void *)&lu_res); bzero((char *)&prop_res, sizeof(prop_res)); status = clnt_call(cl, _NI_LISTPROPS, xdr_ni_id, &childdir.id, xdr_ni_namelist_res, &prop_res, tv); if (status != NI_OK) { /* can't get proplist! */ free(childdir.key); free(childdir.value); socket_lock(); clnt_destroy(cl); (void)close(sock); socket_unlock(); FD_CLR(sock, &clnt_fdset); /* unprotect client socket */ system_log(LOG_ERR, "tag %s: can't get master's property list for /machines/ip_address=%s", mytag,(char *)inet_ntoa(myinaddr)); return status; } free(childdir.key); free(childdir.value); if (prop_res.status != NI_OK) { /* no /machines! */ socket_lock(); clnt_destroy(cl); (void)close(sock); socket_unlock(); FD_CLR(sock, &clnt_fdset); /* unprotect client socket */ system_log(LOG_ERR, "tag %s: can't get master's property list for /machines/ip_address=%s", mytag,(char *)inet_ntoa(myinaddr)); return prop_res.status; } if (prop_res.ni_namelist_res_u.stuff.values.ni_namelist_len == 0) { /* can't get proplist! */ xdr_free(xdr_ni_namelist_res, (void *)&prop_res); socket_lock(); clnt_destroy(cl); (void)close(sock); socket_unlock(); FD_CLR(sock, &clnt_fdset); /* unprotect client socket */ system_log(LOG_ERR, "tag %s: master has no property list for /machines/ip_address=%s", mytag,(char *)inet_ntoa(myinaddr)); return NI_NOPROP; } /* find "serves" property */ where = ni_namelist_match(prop_res.ni_namelist_res_u.stuff.values, "serves"); xdr_free(xdr_ni_namelist_res, (void *)&prop_res); if (where == NI_INDEX_NULL) { /* no serves property! */ socket_lock(); clnt_destroy(cl); (void)close(sock); socket_unlock(); FD_CLR(sock, &clnt_fdset); /* unprotect client socket */ system_log(LOG_ERR, "tag %s: master has no serves property for /machines/ip_address=%s", mytag,(char *)inet_ntoa(myinaddr)); return NI_NOPROP; } /* fetch serves property */ pa.id = childdir.id; pa.prop_index = where; bzero((char *)&prop_res, sizeof(prop_res)); status = clnt_call(cl, _NI_READPROP, xdr_ni_prop_args, &pa, xdr_ni_namelist_res, &prop_res, tv); if (status != NI_OK) { /* can't get proplist! */ socket_lock(); clnt_destroy(cl); (void)close(sock); socket_unlock(); FD_CLR(sock, &clnt_fdset); /* unprotect client socket */ system_log(LOG_ERR, "tag %s: can't get master's serves property for /machines/ip_address=%s", mytag,(char *)inet_ntoa(myinaddr)); return status; } if (prop_res.status != NI_OK) { /* can't get proplist! */ socket_lock(); clnt_destroy(cl); (void)close(sock); socket_unlock(); FD_CLR(sock, &clnt_fdset); /* unprotect client socket */ system_log(LOG_ERR, "tag %s: can't get master's serves property for /machines/ip_address=%s", mytag,(char *)inet_ntoa(myinaddr)); return prop_res.status; } if (prop_res.ni_namelist_res_u.stuff.values.ni_namelist_len == 0) { /* no values in serves property! */ xdr_free(xdr_ni_namelist_res, (void *)&prop_res); socket_lock(); clnt_destroy(cl); (void)close(sock); socket_unlock(); FD_CLR(sock, &clnt_fdset); /* unprotect client socket */ system_log(LOG_ERR, "tag %s: master has no values for serves property in /machines/ip_address=%s", mytag,(char *)inet_ntoa(myinaddr)); return NI_NOPROP; } /* find my "serves" property */ sprintf(myserves, "./%s", mytag); where = ni_namelist_match(prop_res.ni_namelist_res_u.stuff.values, myserves); xdr_free(xdr_ni_namelist_res, (void *)&prop_res); if (where == NI_INDEX_NULL) { /* no serves property! */ socket_lock(); clnt_destroy(cl); (void)close(sock); socket_unlock(); FD_CLR(sock, &clnt_fdset); /* unprotect client socket */ system_log(LOG_ERR, "tag %s: master has no serves ./%s property in /machines/ip_address=%s", mytag,mytag,(char *)inet_ntoa(myinaddr)); return NI_NONAME; } socket_lock(); clnt_destroy(cl); (void)close(sock); socket_unlock(); FD_CLR(sock, &clnt_fdset); /* unprotect client socket */ return NI_OK; }