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 2015 Gary Mills
24 * Copyright (c) 2001 by Sun Microsystems, Inc.
25 * All rights reserved.
29 #include <sys/syslog.h>
30 #include <sys/types.h>
31 #include <rpc/types.h>
33 #include <rpcsvc/nis.h>
35 #include "db_mindex_c.h"
38 #include "ldap_util.h"
43 * In order not to change the on-disk NIS+ DB format, we need make sure
44 * that XDR does nothing for the new structures added to various C++
49 xdr___nis_table_mapping_t(XDR
*xdrs
, void *t
) {
54 xdr___nisdb_ptr_t(XDR
*xdrs
, void *ptr
) {
59 xdr___nisdb_dictionary_defer_t(XDR
*xdrs
, void *defer
) {
64 xdr___nisdb_rwlock_t(XDR
*xdrs
, void *rw
) {
69 xdr___nisdb_flag_t(XDR
*xdrs
, void *flag
) {
74 * Imported from rpc.nisd/nis_db.c
76 * Special abbreviated XDR string which knows that the namep parameter (mainly
77 * owner and group) has a trailing end which matches the last 'n' characters
78 * in the domainname part. It makes use of those common characters to
79 * encode/decode this information. We append an integer string to the
80 * name to be encoded which denotes the place in the domainname from where the
81 * common string starts. For example, if the name was "foo.my.domain." and the
82 * domainname was "my.domain.", the name would be encoded as "foo.10" because
83 * the length of the common part "my.domain." is 10.
89 nis_name domainname
) /* domainname field from the table */
91 size_t name_len
, dom_len
, min_len
;
92 char buf
[NIS_MAXNAMELEN
];
99 /* Get the start of the common part */
101 name_len
= strlen(name
);
103 return (xdr_nis_name(xdrs
, namep
));
104 dom_len
= strlen(domainname
);
105 min_len
= (name_len
< dom_len
) ? name_len
: dom_len
;
106 for (i
= 1; i
<= min_len
; i
++) {
107 if (name
[name_len
- i
] != domainname
[dom_len
- i
])
111 memcpy(buf
, name
, name_len
- i
);
112 sprintf(buf
+ name_len
- i
, ".%d", dom_len
- i
);
114 return (xdr_nis_name(xdrs
, &tmp
));
118 if (!xdr_nis_name(xdrs
, &tmp
))
120 if ((buf
[0] == NULL
) || buf
[strlen(buf
) - 1] == '.') {
121 /* It is either a FQN or a NULL string */
126 if ((*namep
= strdup(buf
)) == NULL
)
132 /* Now concoct the new name */
133 if ((lenstr
= strrchr(buf
, '.')) == NULL
) {
134 /* something went wrong here */
136 "xdr_nis_name_abbrev: no dot found in %s", buf
);
139 i
= atoi(lenstr
+ 1);
140 strcpy(lenstr
, domainname
+ i
);
144 if ((*namep
= strdup(buf
)) == NULL
)
150 return (xdr_nis_name(xdrs
, namep
));
155 * Imported from rpc.nisd/nis_db.c
157 * special XDR for fetus object. We create the actual object from the
158 * "forming" object plus the table object. We create this special object to
159 * save the following components of the nis_object:
160 * zo_name and zo_domain: replaced by just the length field of 0. We had
161 * to keep the length field for backward compatibility. If we
162 * ever change the object format, we should fix this.
163 * zo_owner and zo_group: we condensed it by abbreviating the common part
164 * shared between the table object and the entry object
165 * en_type: Avoided altogether
166 * zo_type and other en_data: Avoided altogether.
168 * XXX: If the definition of nis_object ever changes, this should be changed.
171 xdr_nis_fetus_object(
173 nis_object
*objp
, /* Entry object */
174 nis_object
*tobj
) /* Table object */
178 if (xdrs
->x_op
== XDR_FREE
)
179 return (xdr_nis_object(xdrs
, objp
));
180 if (!xdr_nis_oid(xdrs
, &objp
->zo_oid
))
184 * While encoding of zo_name, we put 0 in the length field, while for
185 * decoding, we get the name from the table object.
187 if (xdrs
->x_op
== XDR_ENCODE
) {
189 if (!xdr_u_int(xdrs
, &size
))
192 if (!xdr_u_int(xdrs
, &size
))
194 if (size
== 0) { /* shrinked format */
195 /* get the name from the table object */
196 if ((objp
->zo_name
= strdup(tobj
->zo_name
)) == NULL
)
200 * We are opening up the xdr_string implementation here
201 * because we called xdr_u_int() earlier.
203 if ((objp
->zo_name
= (char *)malloc(size
+ 1)) == NULL
)
205 if (!xdr_opaque(xdrs
, objp
->zo_name
, size
))
211 * We use the xdr_nis_name_abbrev() function for both owner
212 * and group which constructs the name from the domain name.
214 if (!xdr_nis_name_abbrev(xdrs
, &objp
->zo_owner
, tobj
->zo_domain
))
216 if (!xdr_nis_name_abbrev(xdrs
, &objp
->zo_group
, tobj
->zo_domain
))
220 * While encoding of zo_domain, we put 0 in the length field, while for
221 * decoding, we get the name from the table object. Same as above for
222 * the name. Could have used a function instead.
224 if (xdrs
->x_op
== XDR_ENCODE
) {
226 if (!xdr_u_int(xdrs
, &size
))
229 if (!xdr_u_int(xdrs
, &size
))
231 if (size
== 0) { /* shrinked format */
232 /* get the name from the table object */
233 if ((objp
->zo_domain
= strdup(tobj
->zo_domain
)) == NULL
)
237 * We are opening up the xdr_string implementation here
238 * because we called xdr_u_int() earlier.
240 if ((objp
->zo_domain
= (char *)malloc(size
+ 1))
243 if (!xdr_opaque(xdrs
, objp
->zo_domain
, size
))
248 if (!xdr_u_int(xdrs
, &objp
->zo_access
))
250 if (!xdr_u_int(xdrs
, &objp
->zo_ttl
))
254 * We know that this is an entry object, so we'll save all the entry_obj
255 * space because we can recreate it later.
257 if (xdrs
->x_op
== XDR_ENCODE
)
259 /* Now for the DECODE case, just handcraft the entries and ignore XDR */
260 objp
->zo_data
.zo_type
= NIS_ENTRY_OBJ
;
261 if ((objp
->zo_data
.objdata_u
.en_data
.en_type
=
262 strdup(tobj
->zo_data
.objdata_u
.ta_data
.ta_type
)) == NULL
)
264 objp
->zo_data
.objdata_u
.en_data
.en_cols
.en_cols_val
= NULL
;
265 objp
->zo_data
.objdata_u
.en_data
.en_cols
.en_cols_len
= 0;
269 static const char *in_directory
= "IN_DIRECTORY";
272 * Given an input NIS+ object, create the kind
273 * of pseudo-entry_obj (with an XDR-encoded nis_object in the
274 * first column) that's stored in the DB. Note that:
276 * If the input object is an entry, it's assumed to have the
277 * columns moved up one step (col 0 in en_cols.en_cols_val[1],
278 * etc.). en_cols.en_cols_val[0] will be overwritten. The
279 * input object will be changed (some pointers set to zero,
282 * 'eo' is assumed to be a pointer to an empty entry_obj (or,
283 * at least, one that can be overwritten). It must not be a
284 * pointer to the entry_obj in 'obj'. If the input object is
285 * of a type other than entry, the 'eo' pointer must have
286 * en_cols.en_cols_val appropriately initialized to an array of
287 * (at least) length one.
289 * 'tobj' is a pointer to the table object for the table for
290 * which the entry_obj is destined. It's needed for entry objects,
291 * but unused for other object types.
294 makePseudoEntryObj(nis_object
*obj
, entry_obj
*eo
, nis_object
*tobj
) {
301 char *myself
= "makePseudoEntryObj";
303 if (obj
== 0 || eo
== 0)
306 if (obj
->zo_data
.zo_type
== NIS_ENTRY_OBJ
) {
307 *eo
= obj
->zo_data
.objdata_u
.en_data
;
311 * To prevent the XDR function from making a copy of
312 * the entry columns, we set the columns structure to
313 * 0 (ie no column data)
315 ecl
= obj
->EN_data
.en_cols
.en_cols_len
;
316 ecv
= obj
->EN_data
.en_cols
.en_cols_val
;
317 obj
->EN_data
.en_cols
.en_cols_len
= 0;
318 obj
->EN_data
.en_cols
.en_cols_val
= 0;
320 eo
->en_type
= (char *)in_directory
;
323 bufsize
= xdr_sizeof(xdr_nis_object
, obj
);
324 buf
= am(myself
, bufsize
);
326 if (obj
->zo_data
.zo_type
== NIS_ENTRY_OBJ
) {
327 obj
->EN_data
.en_cols
.en_cols_len
= ecl
;
328 obj
->EN_data
.en_cols
.en_cols_val
= ecv
;
333 xdrmem_create(&xdrs
, (char *)buf
, bufsize
, XDR_ENCODE
);
335 if (obj
->zo_data
.zo_type
== NIS_ENTRY_OBJ
) {
336 xret
= xdr_nis_fetus_object(&xdrs
, obj
, tobj
);
338 xret
= xdr_nis_object(&xdrs
, obj
);
341 /* Restore the 'obj' */
342 if (obj
->zo_data
.zo_type
== NIS_ENTRY_OBJ
) {
343 obj
->EN_data
.en_cols
.en_cols_len
= ecl
;
344 obj
->EN_data
.en_cols
.en_cols_val
= ecv
;
348 logmsg(MSG_NOTIMECHECK
, LOG_ERR
,
349 "%s: XDR encode failure", myself
);
354 eo
->en_cols
.en_cols_val
[0].ec_value
.ec_value_val
= buf
;
355 eo
->en_cols
.en_cols_val
[0].ec_value
.ec_value_len
= xdr_getpos(&xdrs
);
356 eo
->en_cols
.en_cols_val
[0].ec_flags
= EN_BINARY
+EN_XDR
;
362 unmakePseudoEntryObj(entry_obj
*e
, nis_object
*tobj
) {
366 char *myself
= "unmakePseudoEntryObj";
368 if (e
== 0 || e
->en_cols
.en_cols_val
== 0 ||
369 e
->en_cols
.en_cols_len
== 0)
372 o
= am(myself
, sizeof (*o
));
376 xdrmem_create(&xdrs
, e
->en_cols
.en_cols_val
[0].ec_value
.ec_value_val
,
377 e
->en_cols
.en_cols_val
[0].ec_value
.ec_value_len
,
380 if (tobj
!= 0 && (e
->en_type
== 0 || e
->en_type
[0] == '\0')) {
381 stat
= xdr_nis_fetus_object(&xdrs
, o
, tobj
);
383 stat
= xdr_nis_object(&xdrs
, o
);
392 * If it's an entry object, construct the column information.
393 * We make this a copy, so that 'o' can be freed using
394 * nis_destroy_object().
396 if (o
!= 0 && o
->zo_data
.zo_type
== NIS_ENTRY_OBJ
&&
397 o
->zo_data
.objdata_u
.en_data
.en_cols
.en_cols_val
== 0 &&
398 e
->en_cols
.en_cols_len
> 1) {
402 ec
= am(myself
, (e
->en_cols
.en_cols_len
- 1) * sizeof (ec
[0]));
404 nis_destroy_object(o
);
408 o
->zo_data
.objdata_u
.en_data
.en_cols
.en_cols_val
= ec
;
409 o
->zo_data
.objdata_u
.en_data
.en_cols
.en_cols_len
= 0;
410 ocl
= &o
->zo_data
.objdata_u
.en_data
.en_cols
.en_cols_len
;
411 oec
= e
->en_cols
.en_cols_val
;
413 for (i
= 1; i
< e
->en_cols
.en_cols_len
; i
++) {
416 if (oec
[i
].ec_value
.ec_value_val
!= 0) {
417 len
= oec
[i
].ec_value
.ec_value_len
;
420 ec
[i
-1].ec_value
.ec_value_val
= am(myself
, len
);
421 if (ec
[i
-1].ec_value
.ec_value_val
== 0) {
422 nis_destroy_object(o
);
425 (void) memcpy(ec
[i
-1].ec_value
.ec_value_val
,
426 oec
[i
].ec_value
.ec_value_val
,
427 oec
[i
].ec_value
.ec_value_len
);
428 ec
[i
-1].ec_value
.ec_value_len
=
429 oec
[i
].ec_value
.ec_value_len
;
431 ec
[i
-1].ec_value
.ec_value_val
= 0;
432 ec
[i
-1].ec_value
.ec_value_len
= 0;
439 * If it's an entry, and we have the table object, make sure
440 * zo_name and en_type either already are set, or get them
443 if (o
!= 0 && o
->zo_data
.zo_type
== NIS_ENTRY_OBJ
&& tobj
!= 0) {
445 o
->zo_name
= sdup(myself
, T
, tobj
->zo_name
);
446 if (o
->zo_data
.objdata_u
.en_data
.en_type
== 0)
447 o
->zo_data
.objdata_u
.en_data
.en_type
= sdup(myself
, T
,
448 tobj
->zo_data
.objdata_u
.ta_data
.ta_type
);
455 * Input: A (nis_object *), and (optionally) an (entry_obj *) array.
456 * Output: Pointer to an XDR:ed version of an (xdr_nis_object_t).
459 xdrNisObject(nis_object
*obj
, entry_obj
**ea
, int numEa
, int *xdrLenP
) {
460 xdr_nis_object_t xno
;
465 char *myself
= "xdrNisObject";
471 * The version tells us what the XDR:ed buffer contains.
472 * Should be incremented whenever xdr_nis_object_t changes
479 if (obj
->zo_data
.zo_type
== NIS_DIRECTORY_OBJ
&&
480 ea
!= 0 && numEa
> 0) {
484 * The ea[] array is expected to contain the kind of
485 * pseudo-entry object stored in the nisdb incarnation
486 * of a NIS+ directory. Column zero contains the XDR:ed
487 * directory entry object (which we ignore), while column
488 * one contains the name of said entry. It's the latter
489 * that we borrow for use in the dirEntry[] list of the
493 xno
.dirEntry
.dirEntry_len
= 0;
494 xno
.dirEntry
.dirEntry_val
= am(myself
, numEa
*
495 sizeof (xno
.dirEntry
.dirEntry_val
[0]));
496 if (xno
.dirEntry
.dirEntry_val
== 0)
499 for (i
= 0; i
< numEa
; i
++) {
500 if (ea
[i
] == 0 || ea
[i
]->en_cols
.en_cols_val
== 0 ||
501 ea
[i
]->en_cols
.en_cols_len
!= 2 ||
502 ea
[i
]->en_cols
.en_cols_val
[1].
503 ec_value
.ec_value_len
== 0)
506 * Yes, there's a NUL at the end of the dir entry
509 xno
.dirEntry
.dirEntry_val
[xno
.dirEntry
.dirEntry_len
] =
510 ea
[i
]->en_cols
.en_cols_val
[1].
511 ec_value
.ec_value_val
;
512 xno
.dirEntry
.dirEntry_len
++;
515 /* No directory entries */
516 xno
.dirEntry
.dirEntry_len
= 0;
517 xno
.dirEntry
.dirEntry_val
= 0;
520 xdrLen
= xdr_sizeof(xdr_xdr_nis_object_t
, &xno
);
521 buf
= am(myself
, xdrLen
);
525 xdrmem_create(&xdrs
, (char *)buf
, xdrLen
, XDR_ENCODE
);
527 xret
= xdr_xdr_nis_object_t(&xdrs
, &xno
);
529 sfree(xno
.dirEntry
.dirEntry_val
);
543 * Input: Pointer to an XDR:ed version of an (xdr_nis_object_t).
544 * Output: Pointer to a (nis_object *) and (if the object is a
545 * directory) a pointer to an array of (entry_obj *).
548 unXdrNisObject(void *buf
, int bufLen
, entry_obj
***eaP
, int *numEaP
) {
549 xdr_nis_object_t
*xno
;
555 char *myself
= "unXdrNisObject";
557 if (buf
== 0 || bufLen
<= 0)
560 xno
= am(myself
, sizeof (*xno
));
564 xdrmem_create(&xdrs
, buf
, bufLen
, XDR_DECODE
);
565 xret
= xdr_xdr_nis_object_t(&xdrs
, xno
);
572 switch (xno
->xversion
) {
576 xdr_free(xdr_xdr_nis_object_t
, (char *)xno
);
578 logmsg(MSG_NOTIMECHECK
, LOG_WARNING
,
579 "%s: Unknown xdr_nis_object_t version %d",
580 myself
, xno
->xversion
);
584 if (eaP
!= 0 && numEaP
!= 0 && xno
->dirEntry
.dirEntry_len
> 0 &&
585 xno
->dirEntry
.dirEntry_val
!= 0) {
586 ea
= am(myself
, xno
->dirEntry
.dirEntry_len
* sizeof (ea
[0]));
588 xdr_free(xdr_xdr_nis_object_t
, (char *)xno
);
592 for (numEa
= 0; numEa
< xno
->dirEntry
.dirEntry_len
; numEa
++) {
593 ea
[numEa
] = am(myself
, sizeof (*ea
[numEa
]));
594 if (ea
[numEa
] != 0) {
595 ea
[numEa
]->en_cols
.en_cols_len
= 2;
596 ea
[numEa
]->en_cols
.en_cols_val
= am(myself
,
597 ea
[numEa
]->en_cols
.en_cols_len
*
598 sizeof (ea
[numEa
]->en_cols
.en_cols_val
[0]));
600 if (ea
[numEa
] == 0 ||
601 ea
[numEa
]->en_cols
.en_cols_val
== 0) {
603 for (i
= 0; i
< numEa
; i
++) {
604 sfree(ea
[i
]->en_cols
.en_cols_val
);
608 xdr_free(xdr_xdr_nis_object_t
, (char *)xno
);
612 /* Leave column 0 (XDR:ed object) empty */
613 ea
[numEa
]->en_cols
.en_cols_val
[0].
614 ec_value
.ec_value_len
= 0;
615 ea
[numEa
]->en_cols
.en_cols_val
[0].
616 ec_value
.ec_value_val
= 0;
618 * Fill in name of dir entry. The DB counts the NUL
619 * as part of the dir entry name; hence, add one
620 * to the string length.
622 ea
[numEa
]->en_cols
.en_cols_val
[1].
623 ec_value
.ec_value_len
= slen(xno
->dirEntry
.
624 dirEntry_val
[numEa
]) + 1;
625 ea
[numEa
]->en_cols
.en_cols_val
[1].
626 ec_value
.ec_value_val
=
627 xno
->dirEntry
.dirEntry_val
[numEa
];
632 * The xno->dirEntry.dirEntry_val[] pointers are duplicated
633 * in 'ea'. Set the xno pointers to zero, so that the xdr_free
634 * doesn't free the 'ea' data.
638 for (i
= 0; i
< numEa
; i
++) {
639 xno
->dirEntry
.dirEntry_val
[i
] = 0;
651 xdr_free(xdr_xdr_nis_object_t
, (char *)xno
);
658 freeEntryObjArray(entry_obj
**ea
, int numEa
) {
664 for (i
= 0; i
< numEa
; i
++) {
667 for (j
= 0; j
< ea
[i
]->en_cols
.en_cols_len
; j
++) {
668 sfree(ea
[i
]->en_cols
.en_cols_val
[j
].
669 ec_value
.ec_value_val
);
672 sfree(ea
[i
]->en_cols
.en_cols_val
);
679 * Return TRUE if 'o1' and 'o2' are the same, FALSE otherwise.
680 * We perform the comparison by XDR encoding the objects, and then
681 * checking the XDR buffers for equality. However, we don't want to
682 * include the zo_oid (i.e., ctime and mtime) in the comparison.
685 sameNisPlusObj(nis_object
*o1
, nis_object
*o2
) {
690 nis_object obj1
, obj2
;
691 char *myself
= "sameNisPlusObj";
695 else if (o1
== 0 || o2
== 0)
699 * We want to exclude the zo_oid from the comparison. In order
700 * not to modify the objects (even very briefly), we do this by
701 * making copies (nis_object itself only, not the underlying
702 * structures accessed through pointers), and setting the zo_oid
703 * to zero in the copies.
707 obj1
.zo_oid
.ctime
= obj1
.zo_oid
.mtime
= 0;
708 obj2
.zo_oid
.ctime
= obj2
.zo_oid
.mtime
= 0;
710 l1
= xdr_sizeof(xdr_nis_object
, &obj1
);
711 l2
= xdr_sizeof(xdr_nis_object
, &obj2
);
717 if (b1
== 0 || b2
== 0) {
723 xdrmem_create(&x1
, (char *)b1
, l1
, XDR_ENCODE
);
724 xdrmem_create(&x2
, (char *)b2
, l2
, XDR_ENCODE
);
726 if (xdr_nis_object(&x1
, &obj1
) && xdr_nis_object(&x2
, &obj2
)) {
727 ret
= (memcmp(b1
, b2
, l1
) == 0);
729 logmsg(MSG_NOTIMECHECK
, LOG_WARNING
,
730 "%s: xdr_nis_object() error",
742 * A wrapper/convenience function for sameNisPlusObj() that extracts
743 * the object in column zero of 'e2'.
746 sameNisPlusPseudoObj(nis_object
*o1
, entry_obj
*e2
) {
750 if (o1
== 0 && e2
== 0)
755 o2
= unmakePseudoEntryObj(e2
, 0);
757 return ((o1
== 0) ? TRUE
: FALSE
);
759 res
= sameNisPlusObj(o1
, o2
);
761 nis_destroy_object(o2
);