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