]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/security/audit/audit_bsm_token.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / security / audit / audit_bsm_token.c
1 /*-
2  * Copyright (c) 2004 Apple Inc.
3  * Copyright (c) 2005 SPARTA, Inc.
4  * All rights reserved.
5  *
6  * This code was developed in part by Robert N. M. Watson, Senior Principal
7  * Scientist, SPARTA, Inc.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1.  Redistributions of source code must retain the above copyright
13  *     notice, this list of conditions and the following disclaimer.
14  * 2.  Redistributions in binary form must reproduce the above copyright
15  *     notice, this list of conditions and the following disclaimer in the
16  *     documentation and/or other materials provided with the distribution.
17  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
18  *     its contributors may be used to endorse or promote products derived
19  *     from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
25  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36
37 #include <sys/types.h>
38 #include <sys/endian.h>
39 #include <sys/queue.h>
40 #include <sys/socket.h>
41 #include <sys/time.h>
42
43 #include <sys/ipc.h>
44 #include <sys/libkern.h>
45 #include <sys/malloc.h>
46 #include <sys/un.h>
47
48 #include <netinet/in.h>
49 #include <netinet/in_systm.h>
50 #include <netinet/ip.h>
51
52
53 #include <bsm/audit.h>
54 #include <bsm/audit_internal.h>
55 #include <bsm/audit_record.h>
56 #include <security/audit/audit.h>
57 #include <security/audit/audit_private.h>
58
59 #define GET_TOKEN_AREA(t, dptr, length) do {                            \
60         t = malloc(sizeof(token_t), M_AUDITBSM, M_WAITOK);              \
61         t->t_data = malloc(length, M_AUDITBSM, M_WAITOK | M_ZERO);      \
62         t->len = length;                                                \
63         dptr = t->t_data;                                               \
64 } while (0)
65
66 /*
67  * token ID                1 byte
68  * argument #              1 byte
69  * argument value          4 bytes/8 bytes (32-bit/64-bit value)
70  * text length             2 bytes
71  * text                    N bytes + 1 terminating NULL byte
72  */
73 token_t *
74 au_to_arg32(char n, char *text, u_int32_t v)
75 {
76         token_t *t;
77         u_char *dptr = NULL;
78         u_int16_t textlen;
79
80         textlen = strlen(text);
81         textlen += 1;
82
83         GET_TOKEN_AREA(t, dptr, 2 * sizeof(u_char) + sizeof(u_int32_t) +
84             sizeof(u_int16_t) + textlen);
85
86         ADD_U_CHAR(dptr, AUT_ARG32);
87         ADD_U_CHAR(dptr, n);
88         ADD_U_INT32(dptr, v);
89         ADD_U_INT16(dptr, textlen);
90         ADD_STRING(dptr, text, textlen);
91
92         return (t);
93
94 }
95
96 token_t *
97 au_to_arg64(char n, char *text, u_int64_t v)
98 {
99         token_t *t;
100         u_char *dptr = NULL;
101         u_int16_t textlen;
102
103         textlen = strlen(text);
104         textlen += 1;
105
106         GET_TOKEN_AREA(t, dptr, 2 * sizeof(u_char) + sizeof(u_int64_t) +
107             sizeof(u_int16_t) + textlen);
108
109         ADD_U_CHAR(dptr, AUT_ARG64);
110         ADD_U_CHAR(dptr, n);
111         ADD_U_INT64(dptr, v);
112         ADD_U_INT16(dptr, textlen);
113         ADD_STRING(dptr, text, textlen);
114
115         return (t);
116
117 }
118
119 token_t *
120 au_to_arg(char n, char *text, u_int32_t v)
121 {
122
123         return (au_to_arg32(n, text, v));
124 }
125
126 #if defined(_KERNEL) || defined(KERNEL)
127 /*
128  * token ID                1 byte
129  * file access mode        4 bytes
130  * owner user ID           4 bytes
131  * owner group ID          4 bytes
132  * file system ID          4 bytes
133  * node ID                 8 bytes
134  * device                  4 bytes/8 bytes (32-bit/64-bit)
135  */
136 token_t *
137 au_to_attr32(struct vnode_au_info *vni)
138 {
139         token_t *t;
140         u_char *dptr = NULL;
141         u_int16_t pad0_16 = 0;
142         u_int16_t pad0_32 = 0;
143
144         GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 2 * sizeof(u_int16_t) +
145             3 * sizeof(u_int32_t) + sizeof(u_int64_t) + sizeof(u_int32_t));
146
147         ADD_U_CHAR(dptr, AUT_ATTR32);
148
149         /*
150          * Darwin defines the size for the file mode
151          * as 2 bytes; BSM defines 4 so pad with 0
152          */
153         ADD_U_INT16(dptr, pad0_16);
154         ADD_U_INT16(dptr, vni->vn_mode);
155
156         ADD_U_INT32(dptr, vni->vn_uid);
157         ADD_U_INT32(dptr, vni->vn_gid);
158         ADD_U_INT32(dptr, vni->vn_fsid);
159
160         /*
161          * Some systems use 32-bit file ID's, others use 64-bit file IDs.
162          * Attempt to handle both, and let the compiler sort it out.  If we
163          * could pick this out at compile-time, it would be better, so as to
164          * avoid the else case below.
165          */
166         if (sizeof(vni->vn_fileid) == sizeof(uint32_t)) {
167                 ADD_U_INT32(dptr, pad0_32);
168                 ADD_U_INT32(dptr, vni->vn_fileid);
169         } else if (sizeof(vni->vn_fileid) == sizeof(uint64_t))
170                 ADD_U_INT64(dptr, vni->vn_fileid);
171         else
172                 ADD_U_INT64(dptr, 0LL);
173
174         ADD_U_INT32(dptr, vni->vn_dev);
175
176         return (t);
177 }
178
179 token_t *
180 au_to_attr64(struct vnode_au_info *vni)
181 {
182         token_t *t;
183         u_char *dptr = NULL;
184         u_int16_t pad0_16 = 0;
185         u_int16_t pad0_32 = 0;
186
187         GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 2 * sizeof(u_int16_t) +
188             3 * sizeof(u_int32_t) + sizeof(u_int64_t) * 2);
189
190         ADD_U_CHAR(dptr, AUT_ATTR64);
191
192         /*
193          * Darwin defines the size for the file mode
194          * as 2 bytes; BSM defines 4 so pad with 0
195          */
196         ADD_U_INT16(dptr, pad0_16);
197         ADD_U_INT16(dptr, vni->vn_mode);
198
199         ADD_U_INT32(dptr, vni->vn_uid);
200         ADD_U_INT32(dptr, vni->vn_gid);
201         ADD_U_INT32(dptr, vni->vn_fsid);
202
203         /*
204          * Some systems use 32-bit file ID's, other's use 64-bit file IDs.
205          * Attempt to handle both, and let the compiler sort it out.  If we
206          * could pick this out at compile-time, it would be better, so as to
207          * avoid the else case below.
208          */
209         if (sizeof(vni->vn_fileid) == sizeof(uint32_t)) {
210                 ADD_U_INT32(dptr, pad0_32);
211                 ADD_U_INT32(dptr, vni->vn_fileid);
212         } else if (sizeof(vni->vn_fileid) == sizeof(uint64_t))
213                 ADD_U_INT64(dptr, vni->vn_fileid);
214         else
215                 ADD_U_INT64(dptr, 0LL);
216
217         ADD_U_INT64(dptr, vni->vn_dev);
218
219         return (t);
220 }
221
222 token_t *
223 au_to_attr(struct vnode_au_info *vni)
224 {
225
226         return (au_to_attr32(vni));
227 }
228 #endif /* !(defined(_KERNEL) || defined(KERNEL) */
229
230 /*
231  * token ID                1 byte
232  * how to print            1 byte
233  * basic unit              1 byte
234  * unit count              1 byte
235  * data items              (depends on basic unit)
236  */
237 token_t *
238 au_to_data(char unit_print, char unit_type, char unit_count, char *p)
239 {
240         token_t *t;
241         u_char *dptr = NULL;
242         size_t datasize, totdata;
243
244         /* Determine the size of the basic unit. */
245         switch (unit_type) {
246         case AUR_BYTE:
247         /* case AUR_CHAR: */
248                 datasize = AUR_BYTE_SIZE;
249                 break;
250
251         case AUR_SHORT:
252                 datasize = AUR_SHORT_SIZE;
253                 break;
254
255         case AUR_INT32:
256         /* case AUR_INT: */
257                 datasize = AUR_INT32_SIZE;
258                 break;
259
260         case AUR_INT64:
261                 datasize = AUR_INT64_SIZE;
262                 break;
263
264         default:
265                 return (NULL);
266         }
267
268         totdata = datasize * unit_count;
269
270         GET_TOKEN_AREA(t, dptr, 4 * sizeof(u_char) + totdata);
271
272         ADD_U_CHAR(dptr, AUT_DATA);
273         ADD_U_CHAR(dptr, unit_print);
274         ADD_U_CHAR(dptr, unit_type);
275         ADD_U_CHAR(dptr, unit_count);
276         ADD_MEM(dptr, p, totdata);
277
278         return (t);
279 }
280
281
282 /*
283  * token ID                1 byte
284  * status                  4 bytes
285  * return value            4 bytes
286  */
287 token_t *
288 au_to_exit(int retval, int err)
289 {
290         token_t *t;
291         u_char *dptr = NULL;
292
293         GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 2 * sizeof(u_int32_t));
294
295         ADD_U_CHAR(dptr, AUT_EXIT);
296         ADD_U_INT32(dptr, err);
297         ADD_U_INT32(dptr, retval);
298
299         return (t);
300 }
301
302 /*
303  */
304 token_t *
305 au_to_groups(int *groups)
306 {
307
308         return (au_to_newgroups(AUDIT_MAX_GROUPS, (gid_t*)groups));
309 }
310
311 /*
312  * token ID                1 byte
313  * number groups           2 bytes
314  * group list              count * 4 bytes
315  */
316 token_t *
317 au_to_newgroups(u_int16_t n, gid_t *groups)
318 {
319         token_t *t;
320         u_char *dptr = NULL;
321         int i;
322
323         GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int16_t) +
324             n * sizeof(u_int32_t));
325
326         ADD_U_CHAR(dptr, AUT_NEWGROUPS);
327         ADD_U_INT16(dptr, n);
328         for (i = 0; i < n; i++)
329                 ADD_U_INT32(dptr, groups[i]);
330
331         return (t);
332 }
333
334 /*
335  * token ID                1 byte
336  * internet address        4 bytes
337  */
338 token_t *
339 au_to_in_addr(struct in_addr *internet_addr)
340 {
341         token_t *t;
342         u_char *dptr = NULL;
343
344         GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(uint32_t));
345
346         ADD_U_CHAR(dptr, AUT_IN_ADDR);
347         ADD_MEM(dptr, &internet_addr->s_addr, sizeof(uint32_t));
348
349         return (t);
350 }
351
352 /*
353  * token ID                1 byte
354  * address type/length     4 bytes
355  * Address                16 bytes
356  */
357 token_t *
358 au_to_in_addr_ex(struct in6_addr *internet_addr)
359 {
360         token_t *t;
361         u_char *dptr = NULL;
362         u_int32_t type = AU_IPv6;
363
364         GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 5 * sizeof(uint32_t));
365
366         ADD_U_CHAR(dptr, AUT_IN_ADDR_EX);
367         ADD_U_INT32(dptr, type);
368         ADD_MEM(dptr, internet_addr, 4 * sizeof(uint32_t));
369
370         return (t);
371 }
372
373 /*
374  * token ID                1 byte
375  * ip header               20 bytes
376  *
377  * The IP header should be submitted in network byte order.
378  */
379 token_t *
380 au_to_ip(struct ip *ip)
381 {
382         token_t *t;
383         u_char *dptr = NULL;
384
385         GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(struct ip));
386
387         ADD_U_CHAR(dptr, AUT_IP);
388         ADD_MEM(dptr, ip, sizeof(struct ip));
389
390         return (t);
391 }
392
393 /*
394  * token ID                1 byte
395  * object ID type          1 byte
396  * object ID               4 bytes
397  */
398 token_t *
399 au_to_ipc(char type, int id)
400 {
401         token_t *t;
402         u_char *dptr = NULL;
403
404         GET_TOKEN_AREA(t, dptr, 2 * sizeof(u_char) + sizeof(u_int32_t));
405
406         ADD_U_CHAR(dptr, AUT_IPC);
407         ADD_U_CHAR(dptr, type);
408         ADD_U_INT32(dptr, id);
409
410         return (t);
411 }
412
413 /*
414  * token ID                1 byte
415  * owner user ID           4 bytes
416  * owner group ID          4 bytes
417  * creator user ID         4 bytes
418  * creator group ID        4 bytes
419  * access mode             4 bytes
420  * slot sequence #         4 bytes
421  * key                     4 bytes
422  */
423 token_t *
424 au_to_ipc_perm(struct ipc_perm *perm)
425 {
426         token_t *t;
427         u_char *dptr = NULL;
428         u_int16_t pad0 = 0;
429
430         GET_TOKEN_AREA(t, dptr, 12 * sizeof(u_int16_t) + sizeof(u_int32_t));
431
432         ADD_U_CHAR(dptr, AUT_IPC_PERM);
433
434         /*
435          * Darwin defines the sizes for ipc_perm members
436          * as 2 bytes; BSM defines 4 so pad with 0
437          */
438         ADD_U_INT16(dptr, pad0);
439         ADD_U_INT16(dptr, perm->uid);
440
441         ADD_U_INT16(dptr, pad0);
442         ADD_U_INT16(dptr, perm->gid);
443
444         ADD_U_INT16(dptr, pad0);
445         ADD_U_INT16(dptr, perm->cuid);
446
447         ADD_U_INT16(dptr, pad0);
448         ADD_U_INT16(dptr, perm->cgid);
449
450         ADD_U_INT16(dptr, pad0);
451         ADD_U_INT16(dptr, perm->mode);
452
453         ADD_U_INT16(dptr, pad0);
454         ADD_U_INT16(dptr, perm->seq);
455
456         ADD_U_INT32(dptr, perm->key);
457
458         return (t);
459 }
460
461 /*
462  * token ID                1 byte
463  * port IP address         2 bytes
464  */
465 token_t *
466 au_to_iport(u_int16_t iport)
467 {
468         token_t *t;
469         u_char *dptr = NULL;
470
471         GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int16_t));
472
473         ADD_U_CHAR(dptr, AUT_IPORT);
474         ADD_U_INT16(dptr, iport);
475
476         return (t);
477 }
478
479 /*
480  * token ID                1 byte
481  * size                    2 bytes
482  * data                    size bytes
483  */
484 token_t *
485 au_to_opaque(char *data, u_int16_t bytes)
486 {
487         token_t *t;
488         u_char *dptr = NULL;
489
490         GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int16_t) + bytes);
491
492         ADD_U_CHAR(dptr, AUT_OPAQUE);
493         ADD_U_INT16(dptr, bytes);
494         ADD_MEM(dptr, data, bytes);
495
496         return (t);
497 }
498
499 /*
500  * token ID                1 byte
501  * seconds of time         4 bytes
502  * milliseconds of time    4 bytes
503  * file name len           2 bytes
504  * file pathname           N bytes + 1 terminating NULL byte
505  */
506 token_t *
507 au_to_file(char *file, struct timeval tm)
508 {
509         token_t *t;
510         u_char *dptr = NULL;
511         u_int16_t filelen;
512         u_int32_t timems;
513
514         filelen = strlen(file);
515         filelen += 1;
516
517         GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 2 * sizeof(u_int32_t) +
518             sizeof(u_int16_t) + filelen);
519
520         timems = tm.tv_usec/1000;
521
522         ADD_U_CHAR(dptr, AUT_OTHER_FILE32);
523         ADD_U_INT32(dptr, tm.tv_sec);
524         ADD_U_INT32(dptr, timems);      /* We need time in ms. */
525         ADD_U_INT16(dptr, filelen);
526         ADD_STRING(dptr, file, filelen);
527
528         return (t);
529 }
530
531 /*
532  * token ID                1 byte
533  * text length             2 bytes
534  * text                    N bytes + 1 terminating NULL byte
535  */
536 token_t *
537 au_to_text(char *text)
538 {
539         token_t *t;
540         u_char *dptr = NULL;
541         u_int16_t textlen;
542
543         textlen = strlen(text);
544         textlen += 1;
545
546         GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int16_t) + textlen);
547
548         ADD_U_CHAR(dptr, AUT_TEXT);
549         ADD_U_INT16(dptr, textlen);
550         ADD_STRING(dptr, text, textlen);
551
552         return (t);
553 }
554
555 /*
556  * token ID                1 byte
557  * path length             2 bytes
558  * path                    N bytes + 1 terminating NULL byte
559  */
560 token_t *
561 au_to_path(char *text)
562 {
563         token_t *t;
564         u_char *dptr = NULL;
565         u_int16_t textlen;
566
567         textlen = strlen(text);
568         textlen += 1;
569
570         GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int16_t) + textlen);
571
572         ADD_U_CHAR(dptr, AUT_PATH);
573         ADD_U_INT16(dptr, textlen);
574         ADD_STRING(dptr, text, textlen);
575
576         return (t);
577 }
578
579 /*
580  * token ID                1 byte
581  * audit ID                4 bytes
582  * effective user ID       4 bytes
583  * effective group ID      4 bytes
584  * real user ID            4 bytes
585  * real group ID           4 bytes
586  * process ID              4 bytes
587  * session ID              4 bytes
588  * terminal ID
589  *   port ID               4 bytes/8 bytes (32-bit/64-bit value)
590  *   machine address       4 bytes
591  */
592 token_t *
593 au_to_process32(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid,
594     pid_t pid, au_asid_t sid, au_tid_t *tid)
595 {
596         token_t *t;
597         u_char *dptr = NULL;
598
599         GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 9 * sizeof(u_int32_t));
600
601         ADD_U_CHAR(dptr, AUT_PROCESS32);
602         ADD_U_INT32(dptr, auid);
603         ADD_U_INT32(dptr, euid);
604         ADD_U_INT32(dptr, egid);
605         ADD_U_INT32(dptr, ruid);
606         ADD_U_INT32(dptr, rgid);
607         ADD_U_INT32(dptr, pid);
608         ADD_U_INT32(dptr, sid);
609         ADD_U_INT32(dptr, tid->port);
610         ADD_MEM(dptr, &tid->machine, sizeof(u_int32_t));
611
612         return (t);
613 }
614
615 token_t *
616 au_to_process64(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid,
617     pid_t pid, au_asid_t sid, au_tid_t *tid)
618 {
619         token_t *t;
620         u_char *dptr = NULL;
621
622         GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 8 * sizeof(u_int32_t) +
623             sizeof(u_int64_t));
624
625         ADD_U_CHAR(dptr, AUT_PROCESS64);
626         ADD_U_INT32(dptr, auid);
627         ADD_U_INT32(dptr, euid);
628         ADD_U_INT32(dptr, egid);
629         ADD_U_INT32(dptr, ruid);
630         ADD_U_INT32(dptr, rgid);
631         ADD_U_INT32(dptr, pid);
632         ADD_U_INT32(dptr, sid);
633         ADD_U_INT64(dptr, tid->port);
634         ADD_MEM(dptr, &tid->machine, sizeof(u_int32_t));
635
636         return (t);
637 }
638
639 token_t *
640 au_to_process(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid,
641     pid_t pid, au_asid_t sid, au_tid_t *tid)
642 {
643
644         return (au_to_process32(auid, euid, egid, ruid, rgid, pid, sid,
645             tid));
646 }
647
648 /*
649  * token ID                1 byte
650  * audit ID                4 bytes
651  * effective user ID       4 bytes
652  * effective group ID      4 bytes
653  * real user ID            4 bytes
654  * real group ID           4 bytes
655  * process ID              4 bytes
656  * session ID              4 bytes
657  * terminal ID
658  *   port ID               4 bytes/8 bytes (32-bit/64-bit value)
659  *   address type-len      4 bytes
660  *   machine address    4/16 bytes
661  */
662 token_t *
663 au_to_process32_ex(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid,
664     gid_t rgid, pid_t pid, au_asid_t sid, au_tid_addr_t *tid)
665 {
666         token_t *t;
667         u_char *dptr = NULL;
668
669         KASSERT((tid->at_type == AU_IPv4) || (tid->at_type == AU_IPv6),
670             ("au_to_process32_ex: type %u", (unsigned int)tid->at_type));
671         if (tid->at_type == AU_IPv6)
672                 GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 13 *
673                     sizeof(u_int32_t));
674         else
675                 GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 10 *
676                     sizeof(u_int32_t));
677
678         ADD_U_CHAR(dptr, AUT_PROCESS32_EX);
679         ADD_U_INT32(dptr, auid);
680         ADD_U_INT32(dptr, euid);
681         ADD_U_INT32(dptr, egid);
682         ADD_U_INT32(dptr, ruid);
683         ADD_U_INT32(dptr, rgid);
684         ADD_U_INT32(dptr, pid);
685         ADD_U_INT32(dptr, sid);
686         ADD_U_INT32(dptr, tid->at_port);
687         ADD_U_INT32(dptr, tid->at_type);
688         if (tid->at_type == AU_IPv6)
689                 ADD_MEM(dptr, &tid->at_addr[0], 4 * sizeof(u_int32_t));
690         else
691                 ADD_MEM(dptr, &tid->at_addr[0], sizeof(u_int32_t));
692
693         return (t);
694 }
695
696 token_t *
697 au_to_process64_ex(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid,
698     gid_t rgid, pid_t pid, au_asid_t sid, au_tid_addr_t *tid)
699 {
700         token_t *t;
701         u_char *dptr = NULL;
702
703         if (tid->at_type == AU_IPv4)
704                 GET_TOKEN_AREA(t, dptr, sizeof(u_char) +
705                     7 * sizeof(u_int32_t) + sizeof(u_int64_t) +
706                     2 * sizeof(u_int32_t));
707         else if (tid->at_type == AU_IPv6)
708                 GET_TOKEN_AREA(t, dptr, sizeof(u_char) +
709                     7 * sizeof(u_int32_t) + sizeof(u_int64_t) +
710                     5 * sizeof(u_int32_t));
711         else
712                 panic("au_to_process64_ex: invalidate at_type (%d)",
713                     tid->at_type);
714
715         ADD_U_CHAR(dptr, AUT_PROCESS64_EX);
716         ADD_U_INT32(dptr, auid);
717         ADD_U_INT32(dptr, euid);
718         ADD_U_INT32(dptr, egid);
719         ADD_U_INT32(dptr, ruid);
720         ADD_U_INT32(dptr, rgid);
721         ADD_U_INT32(dptr, pid);
722         ADD_U_INT32(dptr, sid);
723         ADD_U_INT64(dptr, tid->at_port);
724         ADD_U_INT32(dptr, tid->at_type);
725         ADD_MEM(dptr, &tid->at_addr[0], sizeof(u_int32_t));
726         if (tid->at_type == AU_IPv6) {
727                 ADD_MEM(dptr, &tid->at_addr[1], sizeof(u_int32_t));
728                 ADD_MEM(dptr, &tid->at_addr[2], sizeof(u_int32_t));
729                 ADD_MEM(dptr, &tid->at_addr[3], sizeof(u_int32_t));
730         }
731
732         return (t);
733 }
734
735 token_t *
736 au_to_process_ex(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid,
737     gid_t rgid, pid_t pid, au_asid_t sid, au_tid_addr_t *tid)
738 {
739
740         return (au_to_process32_ex(auid, euid, egid, ruid, rgid, pid, sid,
741             tid));
742 }
743
744 /*
745  * token ID                1 byte
746  * error status            1 byte
747  * return value            4 bytes/8 bytes (32-bit/64-bit value)
748  */
749 token_t *
750 au_to_return32(char status, u_int32_t ret)
751 {
752         token_t *t;
753         u_char *dptr = NULL;
754
755         GET_TOKEN_AREA(t, dptr, 2 * sizeof(u_char) + sizeof(u_int32_t));
756
757         ADD_U_CHAR(dptr, AUT_RETURN32);
758         ADD_U_CHAR(dptr, status);
759         ADD_U_INT32(dptr, ret);
760
761         return (t);
762 }
763
764 token_t *
765 au_to_return64(char status, u_int64_t ret)
766 {
767         token_t *t;
768         u_char *dptr = NULL;
769
770         GET_TOKEN_AREA(t, dptr, 2 * sizeof(u_char) + sizeof(u_int64_t));
771
772         ADD_U_CHAR(dptr, AUT_RETURN64);
773         ADD_U_CHAR(dptr, status);
774         ADD_U_INT64(dptr, ret);
775
776         return (t);
777 }
778
779 token_t *
780 au_to_return(char status, u_int32_t ret)
781 {
782
783         return (au_to_return32(status, ret));
784 }
785
786 /*
787  * token ID                1 byte
788  * sequence number         4 bytes
789  */
790 token_t *
791 au_to_seq(long audit_count)
792 {
793         token_t *t;
794         u_char *dptr = NULL;
795
796         GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int32_t));
797
798         ADD_U_CHAR(dptr, AUT_SEQ);
799         ADD_U_INT32(dptr, audit_count);
800
801         return (t);
802 }
803
804 /*
805  * token ID                1 byte
806  * socket type             2 bytes
807  * local port              2 bytes
808  * local Internet address  4 bytes
809  * remote port             2 bytes
810  * remote Internet address 4 bytes
811  */
812 token_t *
813 au_to_socket(struct socket *so)
814 {
815
816         /* XXXRW ... */
817         return (NULL);
818 }
819
820 /*
821  * Kernel-specific version of the above function.
822  */
823 #ifdef _KERNEL
824 token_t *
825 kau_to_socket(struct socket_au_info *soi)
826 {
827         token_t *t;
828         u_char *dptr;
829         u_int16_t so_type;
830
831         GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 2 * sizeof(u_int16_t) +
832             sizeof(u_int32_t) + sizeof(u_int16_t) + sizeof(u_int32_t));
833                                                  
834         ADD_U_CHAR(dptr, AU_SOCK_TOKEN);
835         /* Coerce the socket type into a short value */
836         so_type = soi->so_type;
837         ADD_U_INT16(dptr, so_type);
838         ADD_U_INT16(dptr, soi->so_lport);
839         ADD_U_INT32(dptr, soi->so_laddr);
840         ADD_U_INT16(dptr, soi->so_rport);
841         ADD_U_INT32(dptr, soi->so_raddr);
842
843         return (t);
844 }
845 #endif
846
847 /*
848  * token ID                1 byte
849  * socket type             2 bytes
850  * local port              2 bytes
851  * address type/length     4 bytes
852  * local Internet address  4 bytes/16 bytes (IPv4/IPv6 address)
853  * remote port             4 bytes
854  * address type/length     4 bytes
855  * remote Internet address 4 bytes/16 bytes (IPv4/IPv6 address)
856  */
857 token_t *
858 au_to_socket_ex_32(u_int16_t lp, u_int16_t rp, struct sockaddr *la,
859     struct sockaddr *ra)
860 {
861
862         return (NULL);
863 }
864
865 token_t *
866 au_to_socket_ex_128(u_int16_t lp, u_int16_t rp, struct sockaddr *la,
867     struct sockaddr *ra)
868 {
869
870         return (NULL);
871 }
872
873 /*
874  * token ID                1 byte
875  * socket family           2 bytes
876  * path                    104 bytes
877  */
878 token_t *
879 au_to_sock_unix(struct sockaddr_un *so)
880 {
881         token_t *t;
882         u_char *dptr;
883
884         GET_TOKEN_AREA(t, dptr, 3 * sizeof(u_char) + strlen(so->sun_path) + 1);
885
886         ADD_U_CHAR(dptr, AU_SOCK_UNIX_TOKEN);
887         /* BSM token has two bytes for family */
888         ADD_U_CHAR(dptr, 0);
889         ADD_U_CHAR(dptr, so->sun_family);
890         ADD_STRING(dptr, so->sun_path, strlen(so->sun_path) + 1);
891
892         return (t);
893 }
894
895 /*
896  * token ID                1 byte
897  * socket family           2 bytes
898  * local port              2 bytes
899  * socket address          4 bytes
900  */
901 token_t *
902 au_to_sock_inet32(struct sockaddr_in *so)
903 {
904         token_t *t;
905         u_char *dptr = NULL;
906         uint16_t family;
907
908         GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 2 * sizeof(uint16_t) +
909             sizeof(uint32_t));
910
911         ADD_U_CHAR(dptr, AUT_SOCKINET32);
912         /*
913          * BSM defines the family field as 16 bits, but many operating
914          * systems have an 8-bit sin_family field.  Extend to 16 bits before
915          * writing into the token.  Assume that both the port and the address
916          * in the sockaddr_in are already in network byte order, but family
917          * is in local byte order.
918          *
919          * XXXRW: Should a name space conversion be taking place on the value
920          * of sin_family?
921          */
922         family = so->sin_family;
923         ADD_U_INT16(dptr, family);
924         ADD_MEM(dptr, &so->sin_port, sizeof(uint16_t));
925         ADD_MEM(dptr, &so->sin_addr.s_addr, sizeof(uint32_t));
926
927         return (t);
928
929 }
930
931 token_t *
932 au_to_sock_inet128(struct sockaddr_in6 *so)
933 {
934         token_t *t;
935         u_char *dptr = NULL;
936
937         GET_TOKEN_AREA(t, dptr, 3 * sizeof(u_char) + sizeof(u_int16_t) +
938             4 * sizeof(u_int32_t));
939
940         ADD_U_CHAR(dptr, AUT_SOCKINET128);
941         /*
942          * In Darwin, sin6_family is one octet, but BSM defines the token
943          * to store two. So we copy in a 0 first.
944          */
945         ADD_U_CHAR(dptr, 0);
946         ADD_U_CHAR(dptr, so->sin6_family);
947
948         ADD_U_INT16(dptr, so->sin6_port);
949         ADD_MEM(dptr, &so->sin6_addr, 4 * sizeof(uint32_t));
950
951         return (t);
952
953 }
954
955 token_t *
956 au_to_sock_inet(struct sockaddr_in *so)
957 {
958
959         return (au_to_sock_inet32(so));
960 }
961
962 /*
963  * token ID                1 byte
964  * audit ID                4 bytes
965  * effective user ID       4 bytes
966  * effective group ID      4 bytes
967  * real user ID            4 bytes
968  * real group ID           4 bytes
969  * process ID              4 bytes
970  * session ID              4 bytes
971  * terminal ID
972  *   port ID               4 bytes/8 bytes (32-bit/64-bit value)
973  *   machine address       4 bytes
974  */
975 token_t *
976 au_to_subject32(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid,
977     pid_t pid, au_asid_t sid, au_tid_t *tid)
978 {
979         token_t *t;
980         u_char *dptr = NULL;
981
982         GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 9 * sizeof(u_int32_t));
983
984         ADD_U_CHAR(dptr, AUT_SUBJECT32);
985         ADD_U_INT32(dptr, auid);
986         ADD_U_INT32(dptr, euid);
987         ADD_U_INT32(dptr, egid);
988         ADD_U_INT32(dptr, ruid);
989         ADD_U_INT32(dptr, rgid);
990         ADD_U_INT32(dptr, pid);
991         ADD_U_INT32(dptr, sid);
992         ADD_U_INT32(dptr, tid->port);
993         ADD_MEM(dptr, &tid->machine, sizeof(u_int32_t));
994
995         return (t);
996 }
997
998 token_t *
999 au_to_subject64(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid,
1000     pid_t pid, au_asid_t sid, au_tid_t *tid)
1001 {
1002         token_t *t;
1003         u_char *dptr = NULL;
1004
1005         GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 7 * sizeof(u_int32_t) +
1006             sizeof(u_int64_t) + sizeof(u_int32_t));
1007
1008         ADD_U_CHAR(dptr, AUT_SUBJECT64);
1009         ADD_U_INT32(dptr, auid);
1010         ADD_U_INT32(dptr, euid);
1011         ADD_U_INT32(dptr, egid);
1012         ADD_U_INT32(dptr, ruid);
1013         ADD_U_INT32(dptr, rgid);
1014         ADD_U_INT32(dptr, pid);
1015         ADD_U_INT32(dptr, sid);
1016         ADD_U_INT64(dptr, tid->port);
1017         ADD_MEM(dptr, &tid->machine, sizeof(u_int32_t));
1018
1019         return (t);
1020 }
1021
1022 token_t *
1023 au_to_subject(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid, gid_t rgid,
1024     pid_t pid, au_asid_t sid, au_tid_t *tid)
1025 {
1026
1027         return (au_to_subject32(auid, euid, egid, ruid, rgid, pid, sid,
1028             tid));
1029 }
1030
1031 /*
1032  * token ID                1 byte
1033  * audit ID                4 bytes
1034  * effective user ID       4 bytes
1035  * effective group ID      4 bytes
1036  * real user ID            4 bytes
1037  * real group ID           4 bytes
1038  * process ID              4 bytes
1039  * session ID              4 bytes
1040  * terminal ID
1041  *   port ID               4 bytes/8 bytes (32-bit/64-bit value)
1042  *   address type/length   4 bytes
1043  *   machine address    4/16 bytes
1044  */
1045 token_t *
1046 au_to_subject32_ex(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid,
1047     gid_t rgid, pid_t pid, au_asid_t sid, au_tid_addr_t *tid)
1048 {
1049         token_t *t;
1050         u_char *dptr = NULL;
1051
1052         KASSERT((tid->at_type == AU_IPv4) || (tid->at_type == AU_IPv6),
1053             ("au_to_subject32_ex: type %u", (unsigned int)tid->at_type));
1054         if (tid->at_type == AU_IPv6)
1055                 GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 13 *
1056                     sizeof(u_int32_t));
1057         else
1058                 GET_TOKEN_AREA(t, dptr, sizeof(u_char) + 10 *
1059                     sizeof(u_int32_t));
1060
1061         ADD_U_CHAR(dptr, AUT_SUBJECT32_EX);
1062         ADD_U_INT32(dptr, auid);
1063         ADD_U_INT32(dptr, euid);
1064         ADD_U_INT32(dptr, egid);
1065         ADD_U_INT32(dptr, ruid);
1066         ADD_U_INT32(dptr, rgid);
1067         ADD_U_INT32(dptr, pid);
1068         ADD_U_INT32(dptr, sid);
1069         ADD_U_INT32(dptr, tid->at_port);
1070         ADD_U_INT32(dptr, tid->at_type);
1071         if (tid->at_type == AU_IPv6)  
1072                 ADD_MEM(dptr, &tid->at_addr[0], 4 * sizeof(u_int32_t));
1073         else    
1074                 ADD_MEM(dptr, &tid->at_addr[0], sizeof(u_int32_t));
1075
1076         return (t);
1077 }
1078
1079 token_t *
1080 au_to_subject64_ex(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid,
1081     gid_t rgid, pid_t pid, au_asid_t sid, au_tid_addr_t *tid)
1082 {
1083         token_t *t;
1084         u_char *dptr = NULL;
1085
1086         if (tid->at_type == AU_IPv4)
1087                 GET_TOKEN_AREA(t, dptr, sizeof(u_char) +
1088                     7 * sizeof(u_int32_t) + sizeof(u_int64_t) +
1089                     2 * sizeof(u_int32_t));
1090         else if (tid->at_type == AU_IPv6)
1091                 GET_TOKEN_AREA(t, dptr, sizeof(u_char) +
1092                     7 * sizeof(u_int32_t) + sizeof(u_int64_t) +
1093                     5 * sizeof(u_int32_t));
1094         else
1095                 panic("au_to_subject64_ex: invalid at_type (%d)",
1096                     tid->at_type);
1097
1098         ADD_U_CHAR(dptr, AUT_SUBJECT64_EX);
1099         ADD_U_INT32(dptr, auid);
1100         ADD_U_INT32(dptr, euid);
1101         ADD_U_INT32(dptr, egid);
1102         ADD_U_INT32(dptr, ruid);
1103         ADD_U_INT32(dptr, rgid);
1104         ADD_U_INT32(dptr, pid);
1105         ADD_U_INT32(dptr, sid);
1106         ADD_U_INT64(dptr, tid->at_port);
1107         ADD_U_INT32(dptr, tid->at_type);
1108         if (tid->at_type == AU_IPv6)
1109                 ADD_MEM(dptr, &tid->at_addr[0], 4 * sizeof(u_int32_t));
1110         else
1111                 ADD_MEM(dptr, &tid->at_addr[0], sizeof(u_int32_t));
1112
1113         return (t);
1114 }
1115
1116 token_t *
1117 au_to_subject_ex(au_id_t auid, uid_t euid, gid_t egid, uid_t ruid,
1118     gid_t rgid, pid_t pid, au_asid_t sid, au_tid_addr_t *tid)
1119 {
1120
1121         return (au_to_subject32_ex(auid, euid, egid, ruid, rgid, pid, sid,
1122             tid));
1123 }
1124
1125 #if !defined(_KERNEL) && !defined(KERNEL) && defined(HAVE_AUDIT_SYSCALLS)
1126 /*
1127  * Collects audit information for the current process
1128  * and creates a subject token from it
1129  */
1130 token_t *
1131 au_to_me(void)
1132 {
1133         auditinfo_t auinfo;
1134
1135         if (getaudit(&auinfo) != 0)
1136                 return (NULL);
1137
1138         return (au_to_subject32(auinfo.ai_auid, geteuid(), getegid(),
1139             getuid(), getgid(), getpid(), auinfo.ai_asid, &auinfo.ai_termid));
1140 }
1141 #endif
1142
1143 #if defined(_KERNEL) || defined(KERNEL)
1144 static token_t *
1145 au_to_exec_strings(char *strs, int count, u_char type)
1146 {
1147         token_t *t;
1148         u_char *dptr = NULL;
1149         u_int32_t totlen;
1150         int ctr;
1151         char *p;
1152
1153         totlen = 0;
1154         ctr = count;
1155         p = strs;
1156         while (ctr-- > 0) {
1157                 totlen += strlen(p) + 1;
1158                 p = strs + totlen;
1159         }
1160         GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int32_t) + totlen);
1161         ADD_U_CHAR(dptr, type);
1162         ADD_U_INT32(dptr, count);
1163         ADD_STRING(dptr, strs, totlen);
1164
1165         return (t);
1166 }
1167
1168 /*
1169  * token ID                             1 byte
1170  * count                                4 bytes
1171  * text                                 count null-terminated strings
1172  */
1173 token_t *
1174 au_to_exec_args(char *args, int argc)
1175 {
1176
1177         return (au_to_exec_strings(args, argc, AUT_EXEC_ARGS));
1178 }
1179
1180 /*
1181  * token ID                             1 byte
1182  * count                                4 bytes
1183  * text                                 count null-terminated strings
1184  */
1185 token_t *
1186 au_to_exec_env(char *envs, int envc)
1187 {
1188
1189         return (au_to_exec_strings(envs, envc, AUT_EXEC_ENV));
1190 }
1191 #else
1192 /*
1193  * token ID                             1 byte
1194  * count                                4 bytes
1195  * text                                 count null-terminated strings
1196  */
1197 token_t *
1198 au_to_exec_args(char **argv)
1199 {
1200         token_t *t;
1201         u_char *dptr = NULL;
1202         const char *nextarg;
1203         int i, count = 0;
1204         size_t totlen = 0;
1205
1206         nextarg = *argv;
1207
1208         while (nextarg != NULL) {
1209                 int nextlen;
1210
1211                 nextlen = strlen(nextarg);
1212                 totlen += nextlen + 1;
1213                 count++;
1214                 nextarg = *(argv + count);
1215         }
1216
1217         totlen += count * sizeof(char); /* nul terminations. */
1218         GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int32_t) + totlen);
1219
1220         ADD_U_CHAR(dptr, AUT_EXEC_ARGS);
1221         ADD_U_INT32(dptr, count);
1222
1223         for (i = 0; i < count; i++) {
1224                 nextarg = *(argv + i);
1225                 ADD_MEM(dptr, nextarg, strlen(nextarg) + 1);
1226         }
1227
1228         return (t);
1229 }
1230
1231 /*
1232  * token ID                1 byte
1233  * zonename length         2 bytes
1234  * zonename                N bytes + 1 terminating NULL byte
1235  */
1236 token_t *
1237 au_to_zonename(char *zonename)
1238 {
1239         u_char *dptr = NULL;
1240         u_int16_t textlen;
1241         token_t *t;
1242
1243         textlen = strlen(zonename);
1244         textlen += 1;
1245         GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int16_t) + textlen);
1246         ADD_U_CHAR(dptr, AUT_ZONENAME);
1247         ADD_U_INT16(dptr, textlen);
1248         ADD_STRING(dptr, zonename, textlen);
1249         return (t);
1250 }
1251
1252 /*
1253  * token ID                             1 byte
1254  * count                                4 bytes
1255  * text                                 count null-terminated strings
1256  */
1257 token_t *
1258 au_to_exec_env(char **envp)
1259 {
1260         token_t *t;
1261         u_char *dptr = NULL;
1262         int i, count = 0;
1263         size_t totlen = 0;
1264         const char *nextenv;
1265
1266         nextenv = *envp;
1267
1268         while (nextenv != NULL) {
1269                 int nextlen;
1270
1271                 nextlen = strlen(nextenv);
1272                 totlen += nextlen + 1;
1273                 count++;
1274                 nextenv = *(envp + count);
1275         }
1276
1277         totlen += sizeof(char) * count;
1278         GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int32_t) + totlen);
1279
1280         ADD_U_CHAR(dptr, AUT_EXEC_ENV);
1281         ADD_U_INT32(dptr, count);
1282
1283         for (i = 0; i < count; i++) {
1284                 nextenv = *(envp + i);
1285                 ADD_MEM(dptr, nextenv, strlen(nextenv) + 1);
1286         }
1287
1288         return (t);
1289 }
1290 #endif
1291
1292 /*
1293  * token ID                1 byte
1294  * record byte count       4 bytes
1295  * version #               1 byte    [2]
1296  * event type              2 bytes
1297  * event modifier          2 bytes
1298  * seconds of time         4 bytes/8 bytes (32-bit/64-bit value)
1299  * milliseconds of time    4 bytes/8 bytes (32-bit/64-bit value)
1300  */
1301 token_t *
1302 au_to_header32_tm(int rec_size, au_event_t e_type, au_emod_t e_mod,
1303     struct timeval tm)
1304 {
1305         token_t *t;
1306         u_char *dptr = NULL;
1307         u_int32_t timems;
1308
1309         GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int32_t) +
1310             sizeof(u_char) + 2 * sizeof(u_int16_t) + 2 * sizeof(u_int32_t));
1311
1312         ADD_U_CHAR(dptr, AUT_HEADER32);
1313         ADD_U_INT32(dptr, rec_size);
1314         ADD_U_CHAR(dptr, AUDIT_HEADER_VERSION_OPENBSM);
1315         ADD_U_INT16(dptr, e_type);
1316         ADD_U_INT16(dptr, e_mod);
1317
1318         timems = tm.tv_usec/1000;
1319         /* Add the timestamp */
1320         ADD_U_INT32(dptr, tm.tv_sec);
1321         ADD_U_INT32(dptr, timems);      /* We need time in ms. */
1322
1323         return (t);
1324 }
1325
1326 token_t *
1327 au_to_header64_tm(int rec_size, au_event_t e_type, au_emod_t e_mod,
1328     struct timeval tm)
1329 {
1330         token_t *t;
1331         u_char *dptr = NULL;
1332         u_int32_t timems;
1333
1334         GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int32_t) +
1335             sizeof(u_char) + 2 * sizeof(u_int16_t) + 2 * sizeof(u_int64_t));
1336
1337         ADD_U_CHAR(dptr, AUT_HEADER64);
1338         ADD_U_INT32(dptr, rec_size);
1339         ADD_U_CHAR(dptr, AUDIT_HEADER_VERSION_OPENBSM);
1340         ADD_U_INT16(dptr, e_type);
1341         ADD_U_INT16(dptr, e_mod);
1342
1343         timems = tm.tv_usec/1000;
1344         /* Add the timestamp */
1345         ADD_U_INT64(dptr, tm.tv_sec);
1346         ADD_U_INT64(dptr, timems);      /* We need time in ms. */
1347
1348         return (t);
1349 }
1350
1351 /*
1352  * token ID                1 byte
1353  * trailer magic number    2 bytes
1354  * record byte count       4 bytes
1355  */
1356 token_t *
1357 au_to_trailer(int rec_size)
1358 {
1359         token_t *t;
1360         u_char *dptr = NULL;
1361         u_int16_t magic = TRAILER_PAD_MAGIC;
1362
1363         GET_TOKEN_AREA(t, dptr, sizeof(u_char) + sizeof(u_int16_t) +
1364             sizeof(u_int32_t));
1365
1366         ADD_U_CHAR(dptr, AUT_TRAILER);
1367         ADD_U_INT16(dptr, magic);
1368         ADD_U_INT32(dptr, rec_size);
1369
1370         return (t);
1371 }