1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * nis_misc.c 25 */ 26 27 /* 28 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 29 * Use is subject to license terms. 30 */ 31 32 #pragma ident "%Z%%M% %I% %E% SMI" 33 34 /* 35 * nis_misc.c 36 * 37 * This module contains miscellaneous library functions. 38 */ 39 40 #include "mt.h" 41 #include <string.h> 42 #include <syslog.h> 43 #include <malloc.h> 44 #include <rpc/rpc.h> 45 #include <rpcsvc/nis.h> 46 #include <tiuser.h> 47 #include <netdir.h> 48 #include <netinet/in.h> 49 #include <strings.h> 50 #include "nis_clnt.h" 51 #include "nis_local.h" 52 53 static void nis_sort_server_endpoints_inet(nis_server *); 54 extern char *handle_to_server_name(CLIENT *); 55 extern void *__inet_get_local_interfaces(); 56 extern FILE *__nis_debug_file; 57 58 59 /* ARGSUSED */ 60 int 61 __clear_directory_local(nis_name n) 62 { 63 return (1); 64 } 65 66 int (*__clear_directory_ptr)(nis_name) = __clear_directory_local; 67 68 /* 69 * __nis_pingproc() 70 * 71 * This function will send a ping "message" to a remote server. 72 * It doesn't bother to see if there are any results since the ping 73 * is defined to be unreliable. 74 */ 75 void 76 __nis_pingproc( 77 nis_server *srv, /* Server to talk to */ 78 nis_name name, /* Directory that changed */ 79 uint32_t mtime) /* When it changed */ 80 { 81 CLIENT *clnt; 82 ping_args args; 83 struct timeval tv; 84 85 clnt = nis_make_rpchandle(srv, 0, NIS_PROG, NIS_VERSION, 86 ZMH_DG|ZMH_AUTH, 0, 0); 87 if (! clnt) 88 return; 89 90 tv.tv_sec = 0; 91 tv.tv_usec = 0; 92 args.dir = name; 93 args.stamp = mtime; 94 (void) clnt_call(clnt, NIS_PING, xdr_ping_args, (char *)&args, 95 xdr_void, 0, tv); 96 clnt_destroy(clnt); 97 } 98 99 /* 100 * nis_ping() 101 * 102 * This function is used to ping all of the servers that serve a given 103 * directory. The point of the ping is to inform them that something 104 * has changed in the directory and they should go off and find what it 105 * is. Note that we avoid pinging ourselves for optimisation. During a 106 * replica/master switch the location of the master object in the array 107 * will briefly change from server[0] to the offset corresponding to 108 * the new master (the old replica). When everything has settled down 109 * after the switch, the master will once again be in server[0] of the 110 * directory object. The object parameter is optional for clients 111 * (REQUIRED FOR SERVERS) this is the object describing the directory. 112 */ 113 114 void 115 nis_ping(nis_name name, uint32_t mtime, nis_object *obj) 116 { 117 nis_server **srvs; 118 nis_server *s, *list; 119 int i, ns; 120 nis_name thishost = nis_local_host(); 121 122 if (obj) { 123 if (name == 0) 124 name = obj->DI_data.do_name; 125 list = obj->DI_data.do_servers.do_servers_val; 126 ns = obj->DI_data.do_servers.do_servers_len; 127 128 for (i = 0, s = &(list[0]); i < ns; i++, s = &(list[i])) { 129 130 if (nis_dir_cmp(s->name, thishost) == SAME_NAME) { 131 continue; 132 } 133 134 __nis_pingproc(s, name, mtime); 135 } 136 } else { 137 srvs = nis_getservlist(name); 138 if (! srvs) 139 return; 140 141 for (i = 0, s = srvs[0]; s; i++, s = srvs[i]) { 142 143 if (nis_dir_cmp(s->name, thishost) == SAME_NAME) { 144 continue; 145 } 146 __nis_pingproc(s, name, mtime); 147 148 } 149 nis_freeservlist(srvs); 150 } 151 } 152 153 154 /* 155 * nis_dumplog(host, name, time) 156 * 157 * This function will dump log entries from the indicated host to the 158 * caller. It is used by the replica servers to get the updates that have 159 * occurred on a directory since the indicated time. 160 */ 161 162 log_result * 163 nis_dumplog( 164 nis_server *host, /* Server to talk to */ 165 nis_name name, /* Directory name to dump. */ 166 uint32_t dtime) /* Last _valid_ timestamp. */ 167 { 168 CLIENT *clnt; 169 dump_args da; 170 struct timeval tv; 171 enum clnt_stat stat; 172 log_result *result_ptr; 173 174 result_ptr = calloc(1, sizeof (log_result)); 175 if (result_ptr == NULL) { 176 syslog(LOG_ERR, "nis_dumplog: Client out of memory."); 177 return (NULL); 178 } 179 180 clnt = nis_make_rpchandle(host, 0, NIS_PROG, NIS_VERSION, 181 ZMH_VC+ZMH_AUTH, 0, 0); 182 if (! clnt) { 183 result_ptr->lr_status = NIS_NAMEUNREACHABLE; 184 return (result_ptr); 185 } 186 (void) memset((char *)&da, 0, sizeof (da)); 187 da.da_dir = name; 188 da.da_time = dtime; 189 tv.tv_sec = NIS_DUMP_TIMEOUT; 190 tv.tv_usec = 0; 191 stat = clnt_call(clnt, NIS_DUMPLOG, 192 xdr_dump_args, (char *)&da, 193 xdr_log_result, (char *)result_ptr, tv); 194 auth_destroy(clnt->cl_auth); 195 clnt_destroy(clnt); 196 197 /* 198 * Now see if the RPC succeeded. Note that we have 199 * to check for local vs. remote errors in order to 200 * know whether the contents of the log_result record 201 * (result_ptr) are meaningful. 202 */ 203 switch (stat) { 204 case RPC_CANTENCODEARGS: 205 case RPC_CANTDECODERES: 206 case RPC_CANTSEND: 207 case RPC_CANTRECV: 208 case RPC_TIMEDOUT: 209 case RPC_INTR: 210 syslog(LOG_WARNING, "nis_dumplog: RPC error %d", stat); 211 /* 212 * This is a local error, so just return a 213 * generic RPC error. 214 */ 215 result_ptr->lr_status = NIS_RPCERROR; 216 break; 217 218 default: 219 /* 220 * All other return values mean that result_ptr 221 * already has a valid status code. 222 */ 223 break; 224 } 225 226 return (result_ptr); 227 } 228 229 /* 230 * nis_dump(host, name, cback) 231 * 232 * This function will dump an entire directory from the indicated host. 233 * It uses a callback function to minimize the memory requirements on 234 * the client and server. 235 */ 236 237 log_result * 238 nis_dump( 239 nis_server *host, /* Server to talk to */ 240 nis_name name, /* Directory name to dump. */ 241 int (*cback)()) /* Callback function */ 242 { 243 CLIENT *clnt; 244 dump_args da; 245 struct timeval tv; 246 enum clnt_stat stat; 247 int err; 248 log_result *result_ptr; 249 250 result_ptr = calloc(1, sizeof (log_result)); 251 if (result_ptr == NULL) { 252 syslog(LOG_ERR, "nis_dump: Client out of memory."); 253 return (NULL); 254 } 255 256 clnt = nis_make_rpchandle(host, 0, NIS_PROG, NIS_VERSION, 257 ZMH_VC+ZMH_AUTH, 0, 0); 258 if (!clnt) { 259 result_ptr->lr_status = NIS_NAMEUNREACHABLE; 260 return (result_ptr); 261 } 262 (void) mutex_lock(&__nis_callback_lock); 263 (void) memset((char *)&da, 0, sizeof (da)); 264 da.da_dir = name; 265 da.da_time = 0; 266 da.da_cbhost.da_cbhost_len = 1; 267 da.da_cbhost.da_cbhost_val = __nis_init_dump_callback(clnt, cback, 268 NULL); 269 if (! da.da_cbhost.da_cbhost_val) { 270 (void) mutex_unlock(&__nis_callback_lock); 271 result_ptr->lr_status = NIS_CBERROR; 272 auth_destroy(clnt->cl_auth); 273 clnt_destroy(clnt); 274 return (result_ptr); 275 } 276 277 /* 278 * The value of the NIS_DUMP_TIMEOUT is applicable only for the 279 * dump to get initiated. 280 */ 281 tv.tv_sec = NIS_DUMP_TIMEOUT; 282 tv.tv_usec = 0; 283 stat = clnt_call(clnt, NIS_DUMP, xdr_dump_args, (char *)&da, 284 xdr_log_result, (char *)result_ptr, tv); 285 if (stat != RPC_SUCCESS) { 286 result_ptr->lr_status = NIS_RPCERROR; 287 } else if (result_ptr->lr_status == NIS_CBRESULTS) { 288 (*__clear_directory_ptr)(name); 289 err = __nis_run_dump_callback(&(result_ptr->lr_cookie), 290 NIS_CALLBACK, 0, clnt); 291 if (err < 0) 292 result_ptr->lr_status = NIS_CBERROR; 293 } 294 (void) mutex_unlock(&__nis_callback_lock); 295 auth_destroy(clnt->cl_auth); 296 clnt_destroy(clnt); 297 return (result_ptr); 298 } 299 300 /* 301 * Sort server endpoints so that local addresses appear 302 * before remote addresses. 303 */ 304 void 305 nis_sort_directory_servers(directory_obj *slist) 306 { 307 int i; 308 309 int nsvrs = slist->do_servers.do_servers_len; 310 nis_server *svrs = slist->do_servers.do_servers_val; 311 312 for (i = 0; i < nsvrs; i++) { 313 nis_sort_server_endpoints_inet(&svrs[i]); 314 } 315 } 316 317 static 318 int 319 is_local(void *local_interfaces, struct netconfig *ncp, char *uaddr) 320 { 321 return (__inet_uaddr_is_local(local_interfaces, ncp, uaddr)); 322 } 323 324 static 325 int 326 is_remote(void *local_interfaces, struct netconfig *ncp, char *uaddr) 327 { 328 return (!is_local(local_interfaces, ncp, uaddr)); 329 } 330 331 void 332 __nis_swap_endpoints(endpoint *e1, endpoint *e2) 333 { 334 char *t; 335 336 t = e1->uaddr; 337 e1->uaddr = e2->uaddr; 338 e2->uaddr = t; 339 340 t = e1->family; 341 e1->family = e2->family; 342 e2->family = t; 343 344 t = e1->proto; 345 e1->proto = e2->proto; 346 e2->proto = t; 347 } 348 349 /* 350 * Sort a list of server endpoints so that address for local interfaces 351 * occur before remote interfaces. If an error occurs (e.g., no memory), 352 * we just clean up and return; we end up not sorting the endpoints, but 353 * this is just for optimization anyway. 354 * 355 * There is a lot of work in this routine, so it should not be called 356 * frequently. 357 */ 358 static 359 void 360 nis_sort_server_endpoints_inet(nis_server *svr) 361 { 362 int i; 363 int j; 364 int neps = svr->ep.ep_len; 365 endpoint *eps = svr->ep.ep_val; 366 struct netconfig *ncp, *ncp_inet = 0, *ncp_inet6 = 0; 367 void *local_interfaces; 368 void *nch; 369 370 nch = setnetconfig(); 371 if (nch == 0) 372 return; 373 374 /* find any inet entry so we can do uaddr2taddr */ 375 while ((ncp = getnetconfig(nch)) != 0 && 376 ncp_inet == 0 && ncp_inet6 == 0) { 377 if (strcmp(ncp->nc_protofmly, NC_INET) == 0) 378 ncp_inet = ncp; 379 else if (strcmp(ncp->nc_protofmly, NC_INET6)) 380 ncp_inet6 = ncp; 381 } 382 if (ncp_inet == 0 && ncp_inet6 == 0) { 383 (void) endnetconfig(nch); 384 return; 385 } 386 387 local_interfaces = __inet_get_local_interfaces(); 388 if (local_interfaces == 0) { 389 (void) endnetconfig(nch); 390 return; 391 } 392 393 /* 394 * Sort endpoints so local inet addresses are first. The 395 * variable 'i' points to the beginning of the array, 396 * and 'j' points to the end. We advance 'i' as long 397 * as it indexes a non-inet endpoint or a local endpoint. 398 * We retract 'j' as long as it indexes a non-inet endpoint 399 * or a remote endpoint. If either of these cases fail, 400 * then 'i' is pointing at a remote endpoint and 'j' is 401 * pointing at a local endpoint. We swap them, adjust 402 * the indexes, and continue. When the indexes cross 403 * we are done. 404 */ 405 i = 0; 406 j = neps - 1; 407 while (i < j) { 408 if ((strcmp(eps[i].family, NC_INET) != 0 && 409 strcmp(eps[i].family, NC_INET6) != 0) || 410 is_local(local_interfaces, ncp, eps[i].uaddr)) { 411 i++; 412 continue; 413 } 414 415 if ((strcmp(eps[j].family, NC_INET) != 0 && 416 strcmp(eps[j].family, NC_INET6) != 0) || 417 is_remote(local_interfaces, ncp, eps[j].uaddr)) { 418 --j; 419 continue; 420 } 421 422 __nis_swap_endpoints(&eps[i], &eps[j]); 423 i++; 424 --j; 425 } 426 427 /* clean up */ 428 __inet_free_local_interfaces(local_interfaces); 429 (void) endnetconfig(nch); 430 } 431 432 /* 433 * In the pre-IPv6 code, secure RPC has a bug such that it doesn't look 434 * at the endpoint 'family' field when selecting an endpoint to use for 435 * time synchronization. In order to protect that broken code from itself, 436 * we set the endpoint 'proto' to 'nc_netid' (i.e., "udp6" or "tcp6") 437 * rather than 'nc_proto' ("udp"/"tcp") if 'nc_family' is "inet6". 438 * 439 * The __nis_netconfig2ep() and __nis_netconfig_matches_ep() service 440 * functions below simplify endpoint manipulation by implementing the 441 * rules above. 442 */ 443 444 void 445 __nis_netconfig2ep(struct netconfig *nc, endpoint *ep) { 446 447 if (nc == 0 || ep == 0) 448 return; 449 450 ep->family = strdup(nc->nc_protofmly); 451 452 if (strcmp(ep->family, "inet6") == 0) { 453 ep->proto = strdup(nc->nc_netid); 454 } else { 455 ep->proto = strdup(nc->nc_proto); 456 } 457 } 458 459 bool_t 460 __nis_netconfig_matches_ep(struct netconfig *nc, endpoint *ep) { 461 462 if (nc == 0 || ep == 0) 463 return (FALSE); 464 465 if (strcmp(nc->nc_protofmly, ep->family) != 0) 466 return (FALSE); 467 468 if (strcmp(ep->family, "inet6") == 0) 469 return (strcmp(nc->nc_netid, ep->proto) == 0 || 470 strcmp(nc->nc_proto, ep->proto) == 0); 471 else 472 return (strcmp(nc->nc_proto, ep->proto) == 0); 473 474 } 475 476 struct netconfig_list { 477 struct netconfig *nc; 478 struct netconfig_list *next; 479 }; 480 481 static struct netconfig_list *ncl; 482 483 struct netconfig * 484 __nis_get_netconfig(endpoint *ep) 485 { 486 void *nch; 487 struct netconfig *nc; 488 struct netconfig_list *p; 489 490 for (p = ncl; p; p = p->next) { 491 if (__nis_netconfig_matches_ep(p->nc, ep)) { 492 return (p->nc); 493 } 494 } 495 496 nch = setnetconfig(); 497 if (nch == 0) 498 return (0); 499 500 while ((nc = getnetconfig(nch)) != 0) { 501 if (__nis_netconfig_matches_ep(nc, ep)) 502 break; 503 } 504 /* 505 * We call getnetconfigent to allocate a copy of the 506 * netconfig entry. 507 */ 508 if (nc) { 509 p = malloc(sizeof (*p)); 510 if (p == 0) 511 return (0); 512 p->nc = getnetconfigent(nc->nc_netid); 513 p->next = ncl; 514 ncl = p; 515 } 516 (void) endnetconfig(nch); 517 518 return (nc); 519 } 520 521 void 522 nis_free_binding(nis_bound_directory *binding) 523 { 524 xdr_free((xdrproc_t)xdr_nis_bound_directory, (char *)binding); 525 free(binding); 526 } 527 528 void 529 __free_fdresult(fd_result *res) 530 { 531 xdr_free((xdrproc_t)xdr_fd_result, (char *)res); 532 free(res); 533 } 534 535 endpoint * 536 __endpoint_dup(endpoint *src, endpoint *dst) 537 { 538 if (dst == NULL) { 539 dst = malloc(sizeof (endpoint)); 540 if (dst == NULL) 541 return (NULL); 542 } 543 544 dst->family = src->family?strdup(src->family):0; 545 dst->proto = src->proto?strdup(src->proto):0; 546 dst->uaddr = src->uaddr?strdup(src->uaddr):0; 547 548 return (dst); 549 } 550 551 void 552 __endpoint_free(endpoint *ep) 553 { 554 if (ep) { 555 free(ep->family); 556 free(ep->proto); 557 free(ep->uaddr); 558 free(ep); 559 } 560 } 561 562 endpoint * 563 __get_bound_endpoint(nis_bound_directory *binding, int n) 564 { 565 endpoint *ep; 566 nis_server *srv; 567 nis_bound_endpoint *bep; 568 569 bep = &binding->bep_val[n]; 570 srv = binding->dobj.do_servers.do_servers_val; 571 ep = &srv[bep->hostnum].ep.ep_val[bep->epnum]; 572 return (ep); 573 } 574 575 nis_server * 576 __nis_server_dup(nis_server *src, nis_server *dst) 577 { 578 if (dst == NULL) { 579 dst = malloc(sizeof (nis_server)); 580 if (dst == NULL) 581 return (NULL); 582 } 583 (void) memset((char *)dst, 0, sizeof (nis_server)); 584 /* LINTED pointer cast */ 585 return ((nis_server *) 586 __nis_xdr_dup(xdr_nis_server, (char *)src, (char *)dst)); 587 } 588 589 590 char * 591 __nis_xdr_dup(xdrproc_t proc, char *src, char *dst) 592 { 593 uint_t size; 594 char *data; 595 XDR xdrs; 596 597 size = xdr_sizeof(proc, src); 598 data = malloc(size); 599 if (data == NULL) 600 return (NULL); 601 602 xdrmem_create(&xdrs, data, size, XDR_ENCODE); 603 if (!proc(&xdrs, src)) { 604 free(data); 605 return (NULL); 606 } 607 608 xdrmem_create(&xdrs, data, size, XDR_DECODE); 609 if (!proc(&xdrs, dst)) { 610 free(data); 611 return (NULL); 612 } 613 614 free(data); 615 return (dst); 616 } 617 618 void 619 __nis_path_free(char **names, int len) 620 { 621 int i; 622 623 for (i = 0; i < len; i++) 624 free(names[i]); 625 free(names); 626 } 627 628 /* 629 * __nis_path 630 * 631 * Given two path strings, *from and *to, work out the list of names 632 * between them. The length of that path and the pointer to the list 633 * of pointers to the name strings are returned to the caller using 634 * path_length and namesp. As the names list is a pointer to a list of 635 * pointers, the caller must pass the address of the pointer to the 636 * pointer to the list of pointers, hence the unusual "char ***" 637 * type. It is the callers responsibility to free **namesp. 638 */ 639 nis_error 640 __nis_path(char *from, char *to, int *path_length, char ***namesp) 641 { 642 int i; 643 int n; 644 int start; 645 int end; 646 int st, dircmp, lastdircmp; 647 char *tfrom = from; 648 char *tto = to; 649 char **names; 650 651 dircmp = st = nis_dir_cmp(from, to); 652 if (st == BAD_NAME) 653 return (NIS_BADNAME); 654 655 /* figure out how long path is */ 656 n = 0; 657 if (st == HIGHER_NAME) { 658 while ((dircmp = nis_dir_cmp(from, to)) == HIGHER_NAME) { 659 n++; 660 to = nis_domain_of(to); 661 } 662 if (dircmp != SAME_NAME) { 663 /* Unrecoverable error */ 664 dircmp = BAD_NAME; 665 } 666 } else if (st == LOWER_NAME) { 667 from = nis_domain_of(from); 668 while ((dircmp = nis_dir_cmp(from, to)) == LOWER_NAME) { 669 n++; 670 from = nis_domain_of(from); 671 } 672 if (dircmp != SAME_NAME) { 673 /* Unrecoverable error */ 674 dircmp = BAD_NAME; 675 } 676 n++; /* include actual target */ 677 } else if (st == NOT_SEQUENTIAL) { 678 /* names are not sequential */ 679 from = nis_domain_of(from); 680 while ((dircmp = nis_dir_cmp(from, to)) == NOT_SEQUENTIAL) { 681 n++; 682 from = nis_domain_of(from); 683 } 684 n++; /* include common parent */ 685 lastdircmp = dircmp; /* Handle HIGHER or LOWER */ 686 while ((dircmp = nis_dir_cmp(from, to)) == lastdircmp) { 687 n++; 688 lastdircmp = dircmp; 689 to = nis_domain_of(to); 690 } 691 if (dircmp != SAME_NAME) { 692 /* Unrecoverable error */ 693 dircmp = BAD_NAME; 694 } 695 } 696 697 if (dircmp == BAD_NAME) { 698 syslog(LOG_WARNING, "__nis_path: Unable to walk " 699 "from %s to %s", tfrom, tto); 700 return (NIS_BADNAME); 701 } 702 703 names = malloc(n * sizeof (char *)); 704 if (names == NULL) 705 return (NIS_NOMEMORY); 706 707 start = 0; 708 end = n; 709 from = tfrom; 710 to = tto; 711 712 /* 713 * Go through again, this time storing names. 714 * We shouldn't need to check the loops will terminate 715 * on the SAME_NAME condition as we've already checked for 716 * errors in the previous loop. 717 */ 718 if (st == HIGHER_NAME) { 719 while (nis_dir_cmp(from, to) != SAME_NAME) { 720 names[--end] = strdup(to); 721 to = nis_domain_of(to); 722 } 723 } else if (st == LOWER_NAME) { 724 from = nis_domain_of(from); 725 while (nis_dir_cmp(from, to) != SAME_NAME) { 726 names[start++] = strdup(from); 727 from = nis_domain_of(from); 728 } 729 names[start++] = strdup(to); /* include actual target */ 730 } else if (st == NOT_SEQUENTIAL) { 731 /* names are not sequential */ 732 from = nis_domain_of(from); 733 while (nis_dir_cmp(from, to) == NOT_SEQUENTIAL) { 734 names[start++] = strdup(from); 735 from = nis_domain_of(from); 736 } 737 names[start++] = strdup(from); /* include common parent */ 738 while (nis_dir_cmp(from, to) != SAME_NAME) { 739 names[--end] = strdup(to); 740 to = nis_domain_of(to); 741 } 742 } 743 744 /* make sure all of the allocations were successful */ 745 for (i = 0; i < n; i++) { 746 if (names[i] == NULL) { 747 __nis_path_free(names, n); 748 names = NULL; 749 break; 750 } 751 } 752 753 /* Set the return values */ 754 755 *path_length = n; 756 *namesp = names; 757 758 return (NIS_SUCCESS); 759 } 760 761 /* 762 * This is a stub function for clients. There is a version of 763 * it in rpc.nisd that checks to see if the host is listed in 764 * the server list. 765 */ 766 int 767 __nis_host_is_server(nis_server *srv, int nsrv) 768 { 769 #ifdef lint 770 srv = srv; 771 nsrv = nsrv; 772 #endif /* lint */ 773 return (0); 774 } 775 776 char *call_names[] = { 777 "NULL", 778 "NIS_LOOKUP", 779 "NIS_ADD", 780 "NIS_MODIFY", 781 "NIS_REMOVE", 782 "NIS_IBLIST", 783 "NIS_IBADD", 784 "NIS_IBMODIFY", 785 "NIS_IBREMOVE", 786 "NIS_IBFIRST", 787 "NIS_IBNEXT", 788 "13", 789 "NIS_FINDDIRECTORY", 790 "NIS_STATUS", 791 "NIS_DUMPLOG", 792 "NIS_DUMP", 793 "NIS_CALLBACK", 794 "NIS_CPTIME", 795 "NIS_CHECKPOINT", 796 "NIS_PING", 797 "NIS_SERVSTATE", 798 "NIS_MKDIR", 799 "NIS_RMDIR", 800 "NIS_UPDKEYS", 801 }; 802 803 void 804 __nis_print_call(CLIENT *clnt, int proc) 805 { 806 char *name; 807 char *pname; 808 char lbuf[10]; 809 810 name = handle_to_server_name(clnt); 811 if (proc > NIS_UPDKEYS) 812 (void) sprintf(lbuf, "%d", proc); 813 else 814 pname = call_names[proc]; 815 (void) fprintf(__nis_debug_file, "calling server %s for %s\n", 816 name, pname); 817 } 818 819 void 820 __nis_print_rpc_result(enum clnt_stat status) 821 { 822 (void) fprintf(__nis_debug_file, "result: %s\n", clnt_sperrno(status)); 823 } 824 825 void 826 __nis_print_req(ib_request *req) 827 { 828 int i; 829 int nattr = req->ibr_srch.ibr_srch_len; 830 nis_attr *attr = req->ibr_srch.ibr_srch_val; 831 832 (void) fprintf(__nis_debug_file, "["); 833 for (i = 0; i < nattr; i++) { 834 if (i != 0) 835 (void) fprintf(__nis_debug_file, ","); 836 (void) fprintf(__nis_debug_file, "%s=%s", 837 attr[i].zattr_ndx, 838 attr[i].zattr_val.zattr_val_val); 839 } 840 (void) fprintf(__nis_debug_file, "],%s\n", req->ibr_name); 841 } 842 843 void 844 __nis_print_nsreq(ns_request *req) 845 { 846 (void) fprintf(__nis_debug_file, "%s\n", req->ns_name); 847 } 848 849 void 850 __nis_print_result(nis_result *res) 851 { 852 (void) fprintf(__nis_debug_file, 853 "status=%s, %d object%s, [z=%d, d=%d, a=%d, c=%d]\n", 854 nis_sperrno(res->status), 855 res->objects.objects_len, 856 res->objects.objects_len == 1 ? "" : "s", 857 res->zticks, 858 res->dticks, 859 res->aticks, 860 res->cticks); 861 } 862 863 void 864 __nis_print_fdreq(fd_args *arg) 865 { 866 (void) fprintf(__nis_debug_file, "%s (from %s)\n", 867 arg->dir_name, arg->requester); 868 } 869