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
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.
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]
23 * Copyright (c) 2001 by Sun Microsystems, Inc.
24 * All rights reserved.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 #include <sys/syslog.h>
31 #include <sys/types.h>
32 #include <rpc/types.h>
34 #include <rpcsvc/nis.h>
36 #include "db_mindex_c.h"
39 #include "ldap_util.h"
41 extern bool_t
xdr_nis_object();
44 * In order not to change the on-disk NIS+ DB format, we need make sure
45 * that XDR does nothing for the new structures added to various C++
50 xdr___nis_table_mapping_t(XDR
*xdrs
, void *t
) {
55 xdr___nisdb_ptr_t(XDR
*xdrs
, void *ptr
) {
60 xdr___nisdb_dictionary_defer_t(XDR
*xdrs
, void *defer
) {
65 xdr___nisdb_rwlock_t(XDR
*xdrs
, void *rw
) {
70 xdr___nisdb_flag_t(XDR
*xdrs
, void *flag
) {
75 * Imported from rpc.nisd/nis_db.c
77 * Special abbreviated XDR string which knows that the namep parameter (mainly
78 * owner and group) has a trailing end which matches the last 'n' characters
79 * in the domainname part. It makes use of those common characters to
80 * encode/decode this information. We append an integer string to the
81 * name to be encoded which denotes the place in the domainname from where the
82 * common string starts. For example, if the name was "foo.my.domain." and the
83 * domainname was "my.domain.", the name would be encoded as "foo.10" because
84 * the length of the common part "my.domain." is 10.
90 nis_name domainname
) /* domainname field from the table */
92 size_t name_len
, dom_len
, min_len
;
93 char buf
[NIS_MAXNAMELEN
];
100 /* Get the start of the common part */
102 name_len
= strlen(name
);
104 return (xdr_nis_name(xdrs
, namep
));
105 dom_len
= strlen(domainname
);
106 min_len
= (name_len
< dom_len
) ? name_len
: dom_len
;
107 for (i
= 1; i
<= min_len
; i
++) {
108 if (name
[name_len
- i
] != domainname
[dom_len
- i
])
112 memcpy(buf
, name
, name_len
- i
);
113 sprintf(buf
+ name_len
- i
, ".%d", dom_len
- i
);
115 return (xdr_nis_name(xdrs
, &tmp
));
119 if (!xdr_nis_name(xdrs
, &tmp
))
121 if ((buf
[0] == NULL
) || buf
[strlen(buf
) - 1] == '.') {
122 /* It is either a FQN or a NULL string */
127 if ((*namep
= strdup(buf
)) == NULL
)
133 /* Now concoct the new name */
134 if ((lenstr
= strrchr(buf
, '.')) == NULL
) {
135 /* something went wrong here */
137 "xdr_nis_name_abbrev: no dot found in %s", buf
);
140 i
= atoi(lenstr
+ 1);
141 strcpy(lenstr
, domainname
+ i
);
145 if ((*namep
= strdup(buf
)) == NULL
)
151 return (xdr_nis_name(xdrs
, namep
));
156 * Imported from rpc.nisd/nis_db.c
158 * special XDR for fetus object. We create the actual object from the
159 * "forming" object plus the table object. We create this special object to
160 * save the following components of the nis_object:
161 * zo_name and zo_domain: replaced by just the length field of 0. We had
162 * to keep the length field for backward compatibility. If we
163 * ever change the object format, we should fix this.
164 * zo_owner and zo_group: we condensed it by abbreviating the common part
165 * shared between the table object and the entry object
166 * en_type: Avoided altogether
167 * zo_type and other en_data: Avoided altogether.
169 * XXX: If the definition of nis_object ever changes, this should be changed.
172 xdr_nis_fetus_object(
174 nis_object
*objp
, /* Entry object */
175 nis_object
*tobj
) /* Table object */
179 if (xdrs
->x_op
== XDR_FREE
)
180 return (xdr_nis_object(xdrs
, objp
));
181 if (!xdr_nis_oid(xdrs
, &objp
->zo_oid
))
185 * While encoding of zo_name, we put 0 in the length field, while for
186 * decoding, we get the name from the table object.
188 if (xdrs
->x_op
== XDR_ENCODE
) {
190 if (!xdr_u_int(xdrs
, &size
))
193 if (!xdr_u_int(xdrs
, &size
))
195 if (size
== 0) { /* shrinked format */
196 /* get the name from the table object */
197 if ((objp
->zo_name
= strdup(tobj
->zo_name
)) == NULL
)
201 * We are opening up the xdr_string implementation here
202 * because we called xdr_u_int() earlier.
204 if ((objp
->zo_name
= (char *)malloc(size
+ 1)) == NULL
)
206 if (!xdr_opaque(xdrs
, objp
->zo_name
, size
))
212 * We use the xdr_nis_name_abbrev() function for both owner
213 * and group which constructs the name from the domain name.
215 if (!xdr_nis_name_abbrev(xdrs
, &objp
->zo_owner
, tobj
->zo_domain
))
217 if (!xdr_nis_name_abbrev(xdrs
, &objp
->zo_group
, tobj
->zo_domain
))
221 * While encoding of zo_domain, we put 0 in the length field, while for
222 * decoding, we get the name from the table object. Same as above for
223 * the name. Could have used a function instead.
225 if (xdrs
->x_op
== XDR_ENCODE
) {
227 if (!xdr_u_int(xdrs
, &size
))
230 if (!xdr_u_int(xdrs
, &size
))
232 if (size
== 0) { /* shrinked format */
233 /* get the name from the table object */
234 if ((objp
->zo_domain
= strdup(tobj
->zo_domain
)) == NULL
)
238 * We are opening up the xdr_string implementation here
239 * because we called xdr_u_int() earlier.
241 if ((objp
->zo_domain
= (char *)malloc(size
+ 1))
244 if (!xdr_opaque(xdrs
, objp
->zo_domain
, size
))
249 if (!xdr_u_int(xdrs
, &objp
->zo_access
))
251 if (!xdr_u_int(xdrs
, &objp
->zo_ttl
))
255 * We know that this is an entry object, so we'll save all the entry_obj
256 * space because we can recreate it later.
258 if (xdrs
->x_op
== XDR_ENCODE
)
260 /* Now for the DECODE case, just handcraft the entries and ignore XDR */
261 objp
->zo_data
.zo_type
= NIS_ENTRY_OBJ
;
262 if ((objp
->zo_data
.objdata_u
.en_data
.en_type
=
263 strdup(tobj
->zo_data
.objdata_u
.ta_data
.ta_type
)) == NULL
)
265 objp
->zo_data
.objdata_u
.en_data
.en_cols
.en_cols_val
= NULL
;
266 objp
->zo_data
.objdata_u
.en_data
.en_cols
.en_cols_len
= 0;
270 static const char *in_directory
= "IN_DIRECTORY";
273 * Given an input NIS+ object, create the kind
274 * of pseudo-entry_obj (with an XDR-encoded nis_object in the
275 * first column) that's stored in the DB. Note that:
277 * If the input object is an entry, it's assumed to have the
278 * columns moved up one step (col 0 in en_cols.en_cols_val[1],
279 * etc.). en_cols.en_cols_val[0] will be overwritten. The
280 * input object will be changed (some pointers set to zero,
283 * 'eo' is assumed to be a pointer to an empty entry_obj (or,
284 * at least, one that can be overwritten). It must not be a
285 * pointer to the entry_obj in 'obj'. If the input object is
286 * of a type other than entry, the 'eo' pointer must have
287 * en_cols.en_cols_val appropriately initialized to an array of
288 * (at least) length one.
290 * 'tobj' is a pointer to the table object for the table for
291 * which the entry_obj is destined. It's needed for entry objects,
292 * but unused for other object types.
295 makePseudoEntryObj(nis_object
*obj
, entry_obj
*eo
, nis_object
*tobj
) {
302 char *myself
= "makePseudoEntryObj";
304 if (obj
== 0 || eo
== 0)
307 if (obj
->zo_data
.zo_type
== NIS_ENTRY_OBJ
) {
308 *eo
= obj
->zo_data
.objdata_u
.en_data
;
312 * To prevent the XDR function from making a copy of
313 * the entry columns, we set the columns structure to
314 * 0 (ie no column data)
316 ecl
= obj
->EN_data
.en_cols
.en_cols_len
;
317 ecv
= obj
->EN_data
.en_cols
.en_cols_val
;
318 obj
->EN_data
.en_cols
.en_cols_len
= 0;
319 obj
->EN_data
.en_cols
.en_cols_val
= 0;
321 eo
->en_type
= (char *)in_directory
;
324 bufsize
= xdr_sizeof(xdr_nis_object
, obj
);
325 buf
= am(myself
, bufsize
);
327 if (obj
->zo_data
.zo_type
== NIS_ENTRY_OBJ
) {
328 obj
->EN_data
.en_cols
.en_cols_len
= ecl
;
329 obj
->EN_data
.en_cols
.en_cols_val
= ecv
;
334 xdrmem_create(&xdrs
, (char *)buf
, bufsize
, XDR_ENCODE
);
336 if (obj
->zo_data
.zo_type
== NIS_ENTRY_OBJ
) {
337 xret
= xdr_nis_fetus_object(&xdrs
, obj
, tobj
);
339 xret
= xdr_nis_object(&xdrs
, obj
);
342 /* Restore the 'obj' */
343 if (obj
->zo_data
.zo_type
== NIS_ENTRY_OBJ
) {
344 obj
->EN_data
.en_cols
.en_cols_len
= ecl
;
345 obj
->EN_data
.en_cols
.en_cols_val
= ecv
;
349 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
350 "%s: XDR encode failure", myself
);
355 eo
->en_cols
.en_cols_val
[0].ec_value
.ec_value_val
= buf
;
356 eo
->en_cols
.en_cols_val
[0].ec_value
.ec_value_len
= xdr_getpos(&xdrs
);
357 eo
->en_cols
.en_cols_val
[0].ec_flags
= EN_BINARY
+EN_XDR
;
363 unmakePseudoEntryObj(entry_obj
*e
, nis_object
*tobj
) {
367 char *myself
= "unmakePseudoEntryObj";
369 if (e
== 0 || e
->en_cols
.en_cols_val
== 0 ||
370 e
->en_cols
.en_cols_len
== 0)
373 o
= am(myself
, sizeof (*o
));
377 xdrmem_create(&xdrs
, e
->en_cols
.en_cols_val
[0].ec_value
.ec_value_val
,
378 e
->en_cols
.en_cols_val
[0].ec_value
.ec_value_len
,
381 if (tobj
!= 0 && (e
->en_type
== 0 || e
->en_type
[0] == '\0')) {
382 stat
= xdr_nis_fetus_object(&xdrs
, o
, tobj
);
384 stat
= xdr_nis_object(&xdrs
, o
);
393 * If it's an entry object, construct the column information.
394 * We make this a copy, so that 'o' can be freed using
395 * nis_destroy_object().
397 if (o
!= 0 && o
->zo_data
.zo_type
== NIS_ENTRY_OBJ
&&
398 o
->zo_data
.objdata_u
.en_data
.en_cols
.en_cols_val
== 0 &&
399 e
->en_cols
.en_cols_len
> 1) {
403 ec
= am(myself
, (e
->en_cols
.en_cols_len
- 1) * sizeof (ec
[0]));
405 nis_destroy_object(o
);
409 o
->zo_data
.objdata_u
.en_data
.en_cols
.en_cols_val
= ec
;
410 o
->zo_data
.objdata_u
.en_data
.en_cols
.en_cols_len
= 0;
411 ocl
= &o
->zo_data
.objdata_u
.en_data
.en_cols
.en_cols_len
;
412 oec
= e
->en_cols
.en_cols_val
;
414 for (i
= 1; i
< e
->en_cols
.en_cols_len
; i
++) {
417 if (oec
[i
].ec_value
.ec_value_val
!= 0) {
418 len
= oec
[i
].ec_value
.ec_value_len
;
421 ec
[i
-1].ec_value
.ec_value_val
= am(myself
, len
);
422 if (ec
[i
-1].ec_value
.ec_value_val
== 0) {
423 nis_destroy_object(o
);
426 (void) memcpy(ec
[i
-1].ec_value
.ec_value_val
,
427 oec
[i
].ec_value
.ec_value_val
,
428 oec
[i
].ec_value
.ec_value_len
);
429 ec
[i
-1].ec_value
.ec_value_len
=
430 oec
[i
].ec_value
.ec_value_len
;
432 ec
[i
-1].ec_value
.ec_value_val
= 0;
433 ec
[i
-1].ec_value
.ec_value_len
= 0;
440 * If it's an entry, and we have the table object, make sure
441 * zo_name and en_type either already are set, or get them
444 if (o
!= 0 && o
->zo_data
.zo_type
== NIS_ENTRY_OBJ
&& tobj
!= 0) {
446 o
->zo_name
= sdup(myself
, T
, tobj
->zo_name
);
447 if (o
->zo_data
.objdata_u
.en_data
.en_type
== 0)
448 o
->zo_data
.objdata_u
.en_data
.en_type
= sdup(myself
, T
,
449 tobj
->zo_data
.objdata_u
.ta_data
.ta_type
);
456 * Input: A (nis_object *), and (optionally) an (entry_obj *) array.
457 * Output: Pointer to an XDR:ed version of an (xdr_nis_object_t).
460 xdrNisObject(nis_object
*obj
, entry_obj
**ea
, int numEa
, int *xdrLenP
) {
461 xdr_nis_object_t xno
;
466 char *myself
= "xdrNisObject";
472 * The version tells us what the XDR:ed buffer contains.
473 * Should be incremented whenever xdr_nis_object_t changes
480 if (obj
->zo_data
.zo_type
== NIS_DIRECTORY_OBJ
&&
481 ea
!= 0 && numEa
> 0) {
485 * The ea[] array is expected to contain the kind of
486 * pseudo-entry object stored in the nisdb incarnation
487 * of a NIS+ directory. Column zero contains the XDR:ed
488 * directory entry object (which we ignore), while column
489 * one contains the name of said entry. It's the latter
490 * that we borrow for use in the dirEntry[] list of the
494 xno
.dirEntry
.dirEntry_len
= 0;
495 xno
.dirEntry
.dirEntry_val
= am(myself
, numEa
*
496 sizeof (xno
.dirEntry
.dirEntry_val
[0]));
497 if (xno
.dirEntry
.dirEntry_val
== 0)
500 for (i
= 0; i
< numEa
; i
++) {
501 if (ea
[i
] == 0 || ea
[i
]->en_cols
.en_cols_val
== 0 ||
502 ea
[i
]->en_cols
.en_cols_len
!= 2 ||
503 ea
[i
]->en_cols
.en_cols_val
[1].
504 ec_value
.ec_value_len
== 0)
507 * Yes, there's a NUL at the end of the dir entry
510 xno
.dirEntry
.dirEntry_val
[xno
.dirEntry
.dirEntry_len
] =
511 ea
[i
]->en_cols
.en_cols_val
[1].
512 ec_value
.ec_value_val
;
513 xno
.dirEntry
.dirEntry_len
++;
516 /* No directory entries */
517 xno
.dirEntry
.dirEntry_len
= 0;
518 xno
.dirEntry
.dirEntry_val
= 0;
521 xdrLen
= xdr_sizeof(xdr_xdr_nis_object_t
, &xno
);
522 buf
= am(myself
, xdrLen
);
526 xdrmem_create(&xdrs
, (char *)buf
, xdrLen
, XDR_ENCODE
);
528 xret
= xdr_xdr_nis_object_t(&xdrs
, &xno
);
530 sfree(xno
.dirEntry
.dirEntry_val
);
544 * Input: Pointer to an XDR:ed version of an (xdr_nis_object_t).
545 * Output: Pointer to a (nis_object *) and (if the object is a
546 * directory) a pointer to an array of (entry_obj *).
549 unXdrNisObject(void *buf
, int bufLen
, entry_obj
***eaP
, int *numEaP
) {
550 xdr_nis_object_t
*xno
;
556 char *myself
= "unXdrNisObject";
558 if (buf
== 0 || bufLen
<= 0)
561 xno
= am(myself
, sizeof (*xno
));
565 xdrmem_create(&xdrs
, buf
, bufLen
, XDR_DECODE
);
566 xret
= xdr_xdr_nis_object_t(&xdrs
, xno
);
573 switch (xno
->xversion
) {
577 xdr_free(xdr_xdr_nis_object_t
, (char *)xno
);
579 logmsg(MSG_NOTIMECHECK
, LOG_WARNING
,
580 "%s: Unknown xdr_nis_object_t version %d",
581 myself
, xno
->xversion
);
585 if (eaP
!= 0 && numEaP
!= 0 && xno
->dirEntry
.dirEntry_len
> 0 &&
586 xno
->dirEntry
.dirEntry_val
!= 0) {
587 ea
= am(myself
, xno
->dirEntry
.dirEntry_len
* sizeof (ea
[0]));
589 xdr_free(xdr_xdr_nis_object_t
, (char *)xno
);
593 for (numEa
= 0; numEa
< xno
->dirEntry
.dirEntry_len
; numEa
++) {
594 ea
[numEa
] = am(myself
, sizeof (*ea
[numEa
]));
595 if (ea
[numEa
] != 0) {
596 ea
[numEa
]->en_cols
.en_cols_len
= 2;
597 ea
[numEa
]->en_cols
.en_cols_val
= am(myself
,
598 ea
[numEa
]->en_cols
.en_cols_len
*
599 sizeof (ea
[numEa
]->en_cols
.en_cols_val
[0]));
601 if (ea
[numEa
] == 0 ||
602 ea
[numEa
]->en_cols
.en_cols_val
== 0) {
604 for (i
= 0; i
< numEa
; i
++) {
605 sfree(ea
[i
]->en_cols
.en_cols_val
);
609 xdr_free(xdr_xdr_nis_object_t
, (char *)xno
);
613 /* Leave column 0 (XDR:ed object) empty */
614 ea
[numEa
]->en_cols
.en_cols_val
[0].
615 ec_value
.ec_value_len
= 0;
616 ea
[numEa
]->en_cols
.en_cols_val
[0].
617 ec_value
.ec_value_val
= 0;
619 * Fill in name of dir entry. The DB counts the NUL
620 * as part of the dir entry name; hence, add one
621 * to the string length.
623 ea
[numEa
]->en_cols
.en_cols_val
[1].
624 ec_value
.ec_value_len
= slen(xno
->dirEntry
.
625 dirEntry_val
[numEa
]) + 1;
626 ea
[numEa
]->en_cols
.en_cols_val
[1].
627 ec_value
.ec_value_val
=
628 xno
->dirEntry
.dirEntry_val
[numEa
];
633 * The xno->dirEntry.dirEntry_val[] pointers are duplicated
634 * in 'ea'. Set the xno pointers to zero, so that the xdr_free
635 * doesn't free the 'ea' data.
639 for (i
= 0; i
< numEa
; i
++) {
640 xno
->dirEntry
.dirEntry_val
[i
] = 0;
652 xdr_free(xdr_xdr_nis_object_t
, (char *)xno
);
659 freeEntryObjArray(entry_obj
**ea
, int numEa
) {
665 for (i
= 0; i
< numEa
; i
++) {
668 for (j
= 0; j
< ea
[i
]->en_cols
.en_cols_len
; j
++) {
669 sfree(ea
[i
]->en_cols
.en_cols_val
[j
].
670 ec_value
.ec_value_val
);
673 sfree(ea
[i
]->en_cols
.en_cols_val
);
680 * Return TRUE if 'o1' and 'o2' are the same, FALSE otherwise.
681 * We perform the comparison by XDR encoding the objects, and then
682 * checking the XDR buffers for equality. However, we don't want to
683 * include the zo_oid (i.e., ctime and mtime) in the comparison.
686 sameNisPlusObj(nis_object
*o1
, nis_object
*o2
) {
691 nis_object obj1
, obj2
;
692 char *myself
= "sameNisPlusObj";
696 else if (o1
== 0 || o2
== 0)
700 * We want to exclude the zo_oid from the comparison. In order
701 * not to modify the objects (even very briefly), we do this by
702 * making copies (nis_object itself only, not the underlying
703 * structures accessed through pointers), and setting the zo_oid
704 * to zero in the copies.
708 obj1
.zo_oid
.ctime
= obj1
.zo_oid
.mtime
= 0;
709 obj2
.zo_oid
.ctime
= obj2
.zo_oid
.mtime
= 0;
711 l1
= xdr_sizeof(xdr_nis_object
, &obj1
);
712 l2
= xdr_sizeof(xdr_nis_object
, &obj2
);
718 if (b1
== 0 || b2
== 0) {
724 xdrmem_create(&x1
, (char *)b1
, l1
, XDR_ENCODE
);
725 xdrmem_create(&x2
, (char *)b2
, l2
, XDR_ENCODE
);
727 if (xdr_nis_object(&x1
, &obj1
) && xdr_nis_object(&x2
, &obj2
)) {
728 ret
= (memcmp(b1
, b2
, l1
) == 0);
730 logmsg(MSG_NOTIMECHECK
, LOG_WARNING
,
731 "%s: xdr_nis_object() error",
743 * A wrapper/convenience function for sameNisPlusObj() that extracts
744 * the object in column zero of 'e2'.
747 sameNisPlusPseudoObj(nis_object
*o1
, entry_obj
*e2
) {
751 if (o1
== 0 && e2
== 0)
756 o2
= unmakePseudoEntryObj(e2
, 0);
758 return ((o1
== 0) ? TRUE
: FALSE
);
760 res
= sameNisPlusObj(o1
, o2
);
762 nis_destroy_object(o2
);