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 #pragma ident "%Z%%M% %I% %E% SMI"
23 /*
24 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
26 */
27
28 /*LINTLIBRARY*/
29
30 #include <stdio.h>
31 #include <errno.h>
32 #include <string.h>
33 #include <netdb.h>
34 #include <unistd.h>
35 #include <stdlib.h>
36 #include <arpa/inet.h>
37 #include <rpcsvc/ypclnt.h>
38
39 char glob_stdout[BUFSIZ];
40 char glob_stderr[BUFSIZ];
41
42 void f_cleanup(FILE *fp, char *tmpf);
43 void fd_cleanup(int fd1, int fd2);
44 static void _freeList(char ***list);
45
46 extern void **list_append(void **list, void *item);
47
48 #ifdef MAIN
49
50 #define THOSTNAME "cherwell"
51 #define TPRINTERNAME "c"
52
53 int
main()54 main() {
55 char *host = THOSTNAME;
56 const char *user = "cn=Directory Manager";
57 const char *passwd = "directorymanager";
58 int result = 0;
59
60 result = _updateldap("add", host, user, passwd,
61 "_pmTestAuthToken", NULL, NULL, "new comment", "false");
62 if (result != 0) {
63 printf("Add 1 failed, err code = %d\n");
64 }
65
66 result = _updateldap("delete", host, user, passwd,
67 "_pmTestAuthToken", NULL, NULL, NULL, "false");
68 if (result != 0) {
69 printf("Delete 1 failed, err code = %d\n");
70 }
71
72 result = _updateldap("delete", host, user, passwd, TPRINTERNAME,
73 THOSTNAME, "", "new comment", "true");
74 if (result != 0) {
75 printf("delete failed, err code = %d\n");
76 }
77
78 result = _updateldap("delete", host, user, passwd, "_default",
79 THOSTNAME, "", "new comment", "true");
80 if (result != 0) {
81 printf("delete failed, err code = %d\n");
82 }
83
84 result = _updateldap("add", host, user, passwd, TPRINTERNAME,
85 THOSTNAME, "Solaris", "new comment", "true");
86 if (result != 0) {
87 printf("add failed, err code = %d\n");
88 }
89
90 result = _updateldap("modify", host, user, passwd, TPRINTERNAME,
91 THOSTNAME, "", "modified comment", "true");
92 if (result != 0) {
93 printf("modify failed, err code = %d\n");
94 }
95
96 result = _updateldap("modify", host, user, passwd, TPRINTERNAME,
97 THOSTNAME, "", NULL, "false");
98 if (result != 0) {
99 printf("modify failed, err code = %d\n");
100 }
101
102
103 exit(0);
104 }
105 #endif
106
107
108 int
_dorexec(const char * host,const char * user,const char * passwd,const char * cmd,const char * locale)109 _dorexec(
110 const char *host,
111 const char *user,
112 const char *passwd,
113 const char *cmd,
114 const char *locale) {
115
116 int ret = 0;
117 int fd = 0;
118 int fd2 = 1;
119
120 FILE *fderr;
121 char *ferr;
122
123 (void) memset(glob_stdout, 0, BUFSIZ);
124 (void) memset(glob_stderr, 0, BUFSIZ);
125
126 /*
127 * Re-direct stderr to a file
128 */
129 ferr = tempnam(NULL, NULL);
130 if (ferr != NULL) {
131 fderr = freopen(ferr, "w+", stderr);
132 }
133
134 fd = rexec((char **)&host, htons(512), user,
135 passwd, cmd, &fd2);
136
137 if (fd > -1) {
138 /*
139 * rexec worked. Clean up stderr file.
140 */
141 f_cleanup(fderr, ferr);
142
143 ret = read(fd, glob_stdout, BUFSIZ - 1);
144 if (ret < 0) {
145 (void) strncpy(glob_stderr, strerror(errno),
146 (BUFSIZ - 1));
147 fd_cleanup(fd, fd2);
148 return (errno);
149 }
150
151 ret = read(fd2, glob_stderr, BUFSIZ - 1);
152 if (ret < 0) {
153 (void) strncpy(glob_stderr, strerror(errno),
154 (BUFSIZ - 1));
155 fd_cleanup(fd, fd2);
156 return (errno);
157 }
158 } else {
159 /*
160 * rexec failed. Read from the stderr file.
161 */
162 if (fderr != NULL) {
163 char tmpbuf[BUFSIZ];
164
165 (void) rewind(fderr);
166 strcpy(glob_stderr, "");
167 while (fgets(tmpbuf, BUFSIZ - 1,
168 fderr) != NULL) {
169 if ((strlen(glob_stderr) +
170 strlen(tmpbuf)) > BUFSIZ - 1) {
171 break;
172 } else {
173 (void) strcat(glob_stderr, tmpbuf);
174 }
175 }
176 }
177 f_cleanup(fderr, ferr);
178 fd_cleanup(fd, fd2);
179 return (1);
180 }
181 fd_cleanup(fd, fd2);
182 return (0);
183 }
184
185 void
fd_cleanup(int fd,int fd2)186 fd_cleanup(int fd, int fd2)
187 {
188 if (fd > 0) {
189 (void) close(fd);
190 }
191 if (fd2 > 0) {
192 (void) close(fd2);
193 }
194 }
195
196 void
f_cleanup(FILE * fp,char * tmpf)197 f_cleanup(FILE *fp, char *tmpf)
198 {
199 if (fp != NULL) {
200 (void) fclose(fp);
201 }
202 if (tmpf != NULL) {
203 (void) unlink(tmpf);
204 (void) free(tmpf);
205 }
206 }
207
208 struct ns_bsd_addr {
209 char *server; /* server name */
210 char *printer; /* printer name or NULL */
211 char *extension; /* RFC-1179 conformance */
212 char *pname; /* Local printer name */
213 };
214 typedef struct ns_bsd_addr ns_bsd_addr_t;
215
216 /* Key/Value pair structure */
217 struct ns_kvp {
218 char *key; /* key */
219 void *value; /* value converted */
220 };
221 typedef struct ns_kvp ns_kvp_t;
222
223 /*
224 * Information needed to update a name service.
225 * Currently only used for ldap. (see lib/print/ns.h)
226 */
227
228 /* LDAP bind password security type */
229
230 typedef enum NS_PASSWD_TYPE {
231 NS_PW_INSECURE = 0,
232 NS_PW_SECURE = 1
233 } NS_PASSWD_TYPE;
234
235
236 struct ns_cred {
237 char *binddn;
238 char *passwd;
239 char *host;
240 int port; /* LDAP port, 0 = default */
241 NS_PASSWD_TYPE passwdType; /* password security type */
242 uchar_t *domainDN; /* NS domain DN */
243 };
244 typedef struct ns_cred ns_cred_t;
245
246 /* LDAP specific NS Data */
247
248 typedef struct NS_LDAPDATA {
249 char **attrList; /* list of user defined Key Value Pairs */
250 } NS_LDAPDATA;
251
252 /* Printer Object structure */
253 struct ns_printer {
254 char *name; /* primary name of printer */
255 char **aliases; /* aliases for printer */
256 char *source; /* name service derived from */
257 ns_kvp_t **attributes; /* key/value pairs. */
258 ns_cred_t *cred; /* info to update name service */
259 void *nsdata; /* name service specific data */
260 };
261 typedef struct ns_printer ns_printer_t;
262
263 extern ns_printer_t *ns_printer_get_name(const char *, const char *);
264 extern int ns_printer_put(const ns_printer_t *);
265 extern char *ns_get_value_string(const char *, const ns_printer_t *);
266 extern int ns_set_value(const char *, const void *, ns_printer_t *);
267 extern int ns_set_value_from_string(const char *, const char *,
268 ns_printer_t *);
269 extern ns_bsd_addr_t *bsd_addr_create(const char *, const char *,
270 const char *);
271 extern char *bsd_addr_to_string(const ns_bsd_addr_t *);
272 extern void ns_printer_destroy(ns_printer_t *);
273
274 int
_updateoldyp(const char * action,const char * printername,const char * printserver,const char * extensions,const char * comment,const char * isdefault)275 _updateoldyp(
276 const char *action,
277 const char *printername,
278 const char *printserver,
279 const char *extensions,
280 const char *comment,
281 const char *isdefault) {
282
283 ns_printer_t *printer;
284 ns_bsd_addr_t *addr;
285 int status = 0;
286
287 char mkcmd[BUFSIZ];
288 char *domain = NULL;
289 char *host = NULL;
290
291 /*
292 * libprint returns before we know that the printers.conf
293 * map is made. So we'll make it again.
294 */
295 (void) yp_get_default_domain(&domain);
296
297 if ((yp_master(domain, "printers.conf.byname", &host) != 0) &&
298 (yp_master(domain, "passwd.byname", &host) != 0)) {
299 strcpy(mkcmd, "/usr/bin/sleep 1");
300 } else {
301 sprintf(mkcmd, "/usr/bin/rsh -n %s 'cd /var/yp; "
302 "/usr/ccs/bin/make -f /var/yp/Makefile "
303 "-f /var/yp/Makefile.print printers.conf "
304 "> /dev/null'", host);
305 }
306
307 if (strcmp(action, "delete") == 0) {
308 if ((printer = (ns_printer_t *)
309 ns_printer_get_name(printername, "nis")) == NULL) {
310 return (0);
311 }
312
313 printer->attributes = NULL;
314 status = ns_printer_put(printer);
315 if (status != 0) {
316 (void) free(printer);
317 return (status);
318 }
319
320 if ((printer = (ns_printer_t *)
321 ns_printer_get_name("_default", "nis")) != NULL) {
322 char *dflt = (char *)
323 ns_get_value_string("use", printer);
324 if ((dflt != NULL) &&
325 (strcmp(dflt, printername) == 0)) {
326 printer->attributes = NULL;
327 status = ns_printer_put(printer);
328 if (status != 0) {
329 (void) free(printer);
330 return (status);
331 }
332 }
333 }
334 (void) free(printer);
335 (void) system(mkcmd);
336 return (0);
337
338 } else if (strcmp(action, "add") == 0) {
339 printer = (ns_printer_t *)malloc(sizeof (*printer));
340 memset(printer, 0, sizeof (*printer));
341 printer->name = (char *)printername;
342 printer->source = "nis";
343
344 addr = (ns_bsd_addr_t *)malloc(sizeof (*addr));
345 memset(addr, 0, sizeof (*addr));
346 addr->printer = (char *)printername;
347 addr->server = (char *)printserver;
348 if ((extensions != NULL) &&
349 (strlen(extensions) > 0)) {
350 addr->extension = (char *)extensions;
351 }
352 ns_set_value("bsdaddr", addr, printer);
353
354 if ((comment != NULL) && (strlen(comment) > 0)) {
355 ns_set_value_from_string("description",
356 comment, printer);
357 }
358 status = ns_printer_put(printer);
359 if (status != 0) {
360 (void) free(addr);
361 (void) free(printer);
362 return (status);
363 }
364
365 if (strcmp(isdefault, "true") == 0) {
366 printer->name = "_default";
367 printer->attributes = NULL;
368 ns_set_value_from_string("use", printername, printer);
369 status = ns_printer_put(printer);
370 if (status != 0) {
371 (void) free(addr);
372 (void) free(printer);
373 return (status);
374 }
375 }
376 (void) free(addr);
377 (void) free(printer);
378 (void) system(mkcmd);
379 return (0);
380 }
381
382 /*
383 * Modify
384 */
385 if ((printer = (ns_printer_t *)
386 ns_printer_get_name(printername, "nis")) == NULL) {
387 return (1);
388 }
389 if ((comment != NULL) && (strlen(comment) > 0)) {
390 ns_set_value_from_string("description", comment, printer);
391 } else {
392 ns_set_value_from_string("description",
393 NULL, printer);
394 }
395 status = ns_printer_put(printer);
396 if (status != 0) {
397 (void) free(printer);
398 return (status);
399 }
400
401 if ((printer = (ns_printer_t *)
402 ns_printer_get_name("_default", "nis")) != NULL) {
403 char *dflt = (char *)ns_get_value_string("use", printer);
404 if (strcmp(printername, dflt) == 0) {
405 if (strcmp(isdefault, "false") == 0) {
406 /*
407 * We were the default printer but not
408 * any more.
409 */
410 printer->attributes = NULL;
411 status = ns_printer_put(printer);
412 if (status != 0) {
413 (void) free(printer);
414 return (status);
415 }
416 }
417 } else {
418 if (strcmp(isdefault, "true") == 0) {
419 ns_set_value_from_string("use",
420 printername, printer);
421 status = ns_printer_put(printer);
422 if (status != 0) {
423 (void) free(printer);
424 return (status);
425 }
426 }
427 }
428 } else {
429 printer = (ns_printer_t *)malloc(sizeof (*printer));
430 memset(printer, 0, sizeof (*printer));
431 printer->name = "_default";
432 printer->source = "nis";
433 ns_set_value_from_string("use", printername, printer);
434 status = ns_printer_put(printer);
435 if (status != 0) {
436 (void) free(printer);
437 return (status);
438 }
439 }
440 (void) system(mkcmd);
441 return (0);
442 }
443
444 int
_updateldap(const char * action,const char * host,const char * binddn,const char * passwd,const char * printername,const char * printserver,const char * extensions,const char * comment,const char * isdefault)445 _updateldap(
446 const char *action,
447 const char *host,
448 const char *binddn,
449 const char *passwd,
450 const char *printername,
451 const char *printserver,
452 const char *extensions,
453 const char *comment,
454 const char *isdefault)
455
456 {
457 ns_printer_t *printer;
458 ns_bsd_addr_t *addr;
459 ns_cred_t *cred;
460
461 char *item = NULL;
462 char **attrList = NULL;
463
464 int status;
465
466 if (printserver == NULL) {
467 /* printserver not given so use host */
468 printserver = host;
469 }
470
471 cred = (ns_cred_t *)malloc(sizeof (*cred));
472 (void) memset(cred, '\0', sizeof (*cred));
473 cred->passwd = strdup((char *)passwd);
474 cred->binddn = strdup((char *)binddn);
475 cred->host = strdup((char *)host);
476
477 cred->passwdType = NS_PW_INSECURE; /* use default */
478 cred->port = 0; /* use default */
479 cred->domainDN = NULL; /* use default */
480
481 if (strcmp(action, "delete") == 0) {
482 /*
483 * Delete printer object from LDAP directory DIT
484 */
485
486 if ((printer = (ns_printer_t *)
487 ns_printer_get_name(printername, "ldap")) == NULL) {
488 return (0);
489 }
490
491 printer->attributes = NULL;
492 printer->nsdata = malloc(sizeof (NS_LDAPDATA));
493 if (printer->nsdata == NULL) {
494 return (1);
495 }
496 ((NS_LDAPDATA *)(printer->nsdata))->attrList = NULL;
497 printer->cred = cred;
498 printer->source = strdup("ldap");
499 status = ns_printer_put(printer);
500 free(printer->nsdata);
501 (void) ns_printer_destroy(printer);
502
503 if (status != 0) {
504 return (status);
505 }
506
507 if ((printer = (ns_printer_t *)
508 ns_printer_get_name("_default", "ldap")) != NULL) {
509 char *dflt = (char *)
510 ns_get_value_string("use", printer);
511 if ((dflt != NULL) &&
512 (strcmp(dflt, printername) == 0)) {
513 printer->attributes = NULL;
514 printer->nsdata = malloc(sizeof (NS_LDAPDATA));
515 if (printer->nsdata == NULL) {
516 (void) ns_printer_destroy(printer);
517 return (1);
518 }
519 ((NS_LDAPDATA *)(printer->nsdata))->attrList = NULL;
520 printer->cred = cred;
521 printer->source = strdup("ldap");
522 status = ns_printer_put(printer);
523 free(printer->nsdata);
524 if (status != 0) {
525 (void) ns_printer_destroy(printer);
526 return (status);
527 }
528 }
529
530 (void) ns_printer_destroy(printer);
531 }
532 return (0);
533
534 } else if (strcmp(action, "add") == 0) {
535 /*
536 * Add new printer object into LDAP directory DIT
537 */
538
539 printer = (ns_printer_t *)malloc(sizeof (*printer));
540 if (printer == NULL) {
541 return (1);
542 }
543 (void) memset(printer, 0, sizeof (*printer));
544 printer->name = strdup((char *)printername);
545 printer->source = strdup("ldap");
546
547 printer->cred = cred;
548
549 /* set BSD address in attribute list */
550
551 if (extensions == NULL) {
552 item = (char *)malloc(strlen("bsdaddr") +
553 strlen(printserver) +
554 strlen(printername) +
555 strlen("Solaris") + 6);
556 } else {
557 item = (char *)malloc(strlen("bsdaddr") +
558 strlen(printserver) +
559 strlen(printername) +
560 strlen(extensions) + 6);
561 }
562 if (item == NULL) {
563 (void) ns_printer_destroy(printer);
564 return (1);
565 }
566
567 if (extensions == NULL) {
568 sprintf(item, "%s=%s,%s,%s", "bsdaddr",
569 printserver, printername, "Solaris");
570 } else {
571 sprintf(item, "%s=%s,%s,%s", "bsdaddr",
572 printserver, printername, extensions);
573 }
574
575 attrList = (char **)list_append((void**)attrList,
576 (void *)item);
577 if ((comment != NULL) && (strlen(comment) > 0)) {
578 item = (char *)malloc(strlen("description") +
579 strlen(comment) + 4);
580 if (item == NULL) {
581 (void) ns_printer_destroy(printer);
582 return (1);
583 }
584 sprintf(item, "%s=%s", "description", comment);
585 attrList = (char **)list_append((void**)attrList,
586 (void *)item);
587 }
588
589 printer->attributes = NULL;
590 printer->nsdata = malloc(sizeof (NS_LDAPDATA) + 2);
591 if (printer->nsdata == NULL) {
592 (void) ns_printer_destroy(printer);
593 return (1);
594 }
595 ((NS_LDAPDATA *)(printer->nsdata))->attrList = attrList;
596
597 status = ns_printer_put(printer);
598 _freeList(&attrList);
599 if (status != 0) {
600 free(printer->nsdata);
601 (void) ns_printer_destroy(printer);
602 return (status);
603 }
604
605 if (strcmp(isdefault, "true") == 0) {
606 (void) free(printer->name);
607
608 printer->name = strdup("_default");
609 printer->attributes = NULL;
610
611 attrList = NULL;
612 item = (char *)malloc(strlen("use") +
613 strlen(printername) + 4);
614 if (item == NULL) {
615 (void) ns_printer_destroy(printer);
616 return (1);
617 }
618 sprintf(item, "%s=%s", "use", printername);
619 attrList = (char **)list_append((void**)attrList,
620 (void *)item);
621
622 ((NS_LDAPDATA *)(printer->nsdata))->attrList = attrList;
623
624 status = ns_printer_put(printer);
625 _freeList(&attrList);
626 free(printer->nsdata);
627 if (status != 0) {
628 (void) ns_printer_destroy(printer);
629 return (status);
630 }
631 }
632 (void) ns_printer_destroy(printer);
633 return (0);
634 }
635
636 /*
637 * Modify printer object in the LDAP directory DIT
638 */
639
640 if ((printer = (ns_printer_t *)
641 ns_printer_get_name(printername, "ldap")) == NULL) {
642 return (1);
643 }
644 printer->cred = cred;
645 printer->source = strdup("ldap");
646
647 if ((comment != NULL) && (strlen(comment) > 0)) {
648 item = (char *)malloc(strlen("description") +
649 strlen(comment) + 4);
650 if (item == NULL) {
651 (void) ns_printer_destroy(printer);
652 return (1);
653 }
654 sprintf(item, "%s=%s", "description", comment);
655 attrList = (char **)list_append((void**)attrList, (void *)item);
656 } else {
657 item = (char *)malloc(strlen("description") + 4);
658 if (item == NULL) {
659 (void) ns_printer_destroy(printer);
660 return (1);
661 }
662 sprintf(item, "%s=", "description");
663 attrList = (char **)list_append((void**)attrList, (void *)item);
664 }
665
666 printer->attributes = NULL;
667 printer->nsdata = malloc(sizeof (NS_LDAPDATA));
668 if (printer->nsdata == NULL) {
669 (void) ns_printer_destroy(printer);
670 return (1);
671 }
672 ((NS_LDAPDATA *)(printer->nsdata))->attrList = attrList;
673
674 status = ns_printer_put(printer);
675 _freeList(&attrList);
676 free(printer->nsdata);
677 if (status != 0) {
678 (void) ns_printer_destroy(printer);
679 return (status);
680 }
681
682 /*
683 * Handle the default printer.
684 */
685 if ((printer = (ns_printer_t *)
686 ns_printer_get_name("_default", "ldap")) != NULL) {
687 char *dflt = (char *)ns_get_value_string("use", printer);
688
689 printer->source = strdup("ldap");
690 printer->cred = cred;
691 if (strcmp(printername, dflt) == 0) {
692 if (strcmp(isdefault, "false") == 0) {
693 /*
694 * We were the default printer but not
695 * any more. So delete the default entry
696 */
697 printer->attributes = NULL;
698 printer->nsdata = malloc(sizeof (NS_LDAPDATA));
699 if (printer->nsdata == NULL) {
700 (void) ns_printer_destroy(printer);
701 return (1);
702 }
703 ((NS_LDAPDATA *)(printer->nsdata))->attrList = NULL;
704 status = ns_printer_put(printer);
705 free(printer->nsdata);
706 if (status != 0) {
707 (void) ns_printer_destroy(printer);
708 return (status);
709 }
710 }
711 } else if (strcmp(isdefault, "true") == 0) {
712 /*
713 * Modify this default entry to use us.
714 */
715 printer->attributes = NULL;
716 printer->nsdata = malloc(sizeof (NS_LDAPDATA));
717 if (printer->nsdata == NULL) {
718 (void) ns_printer_destroy(printer);
719 return (1);
720 }
721 attrList = NULL;
722 item = (char *)malloc(strlen("use") +
723 strlen(printername) + 4);
724 if (item == NULL) {
725 (void) ns_printer_destroy(printer);
726 return (1);
727 }
728 sprintf(item, "%s=%s", "use", printername);
729 attrList = (char **)list_append((void**)attrList,
730 (void *)item);
731
732 ((NS_LDAPDATA *)(printer->nsdata))->attrList = attrList;
733
734 status = ns_printer_put(printer);
735 _freeList(&attrList);
736 free(printer->nsdata);
737
738 if (status != 0) {
739 (void) ns_printer_destroy(printer);
740 return (status);
741 }
742 }
743 } else if (strcmp(isdefault, "true") == 0) {
744 /*
745 * No default entry existed and we need one.
746 */
747 printer = (ns_printer_t *)malloc(sizeof (*printer));
748 (void) memset(printer, 0, sizeof (*printer));
749 printer->name = strdup("_default");
750 printer->source = strdup("ldap");
751 printer->cred = cred;
752
753 printer->nsdata = malloc(sizeof (NS_LDAPDATA));
754 if (printer->nsdata == NULL) {
755 (void) ns_printer_destroy(printer);
756 return (1);
757 }
758
759 attrList = NULL;
760 item = (char *)malloc(strlen("use") + strlen(printername) + 4);
761 if (item == NULL) {
762 (void) ns_printer_destroy(printer);
763 return (1);
764 }
765 sprintf(item, "%s=%s", "use", printername);
766 attrList = (char **)list_append((void**)attrList, (void *)item);
767
768 ((NS_LDAPDATA *)(printer->nsdata))->attrList = attrList;
769
770 status = ns_printer_put(printer);
771 _freeList(&attrList);
772 free(printer->nsdata);
773
774 if (status != 0) {
775 (void) ns_printer_destroy(printer);
776 return (status);
777 }
778 }
779
780 (void) ns_printer_destroy(printer);
781 return (0);
782 }
783
784
785
786
787 /*
788 * *****************************************************************************
789 *
790 * Function: _freeList()
791 *
792 * Description: Free the list created by list_append() where the items in
793 * the list have been strdup'ed.
794 *
795 * Parameters:
796 * Input: char ***list - returned set of kvp values
797 *
798 * Result: void
799 *
800 * *****************************************************************************
801 */
802
803 static void
_freeList(char *** list)804 _freeList(char ***list)
805
806 {
807 int i = 0;
808
809 /* ------ */
810
811 if (list != NULL) {
812 if (*list != NULL) {
813 for (i = 0; (*list)[i] != NULL; i++) {
814 free((*list)[i]);
815 }
816 free(*list);
817 }
818
819 *list = NULL;
820 }
821 } /* _freeList */
822