1/*
2 * Copyright (c) 2006 Apple Inc.  All Rights Reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29#include <unistd.h>
30#include <stdlib.h>
31#include <stdio.h>
32#include <stdbool.h>
33#include <errno.h>
34#include <string.h>
35
36// add additional headers needed here.
37
38#include "../libmicro.h"
39#include <membership.h>
40#include <pwd.h>
41#include <uuid/uuid.h>
42
43#if DEBUG
44# define debug(fmt, args...)    (void) fprintf(stderr, fmt "\n" , ##args)
45#else
46# define debug(fmt, args...)
47#endif
48
49
50// Correct use case
51//
52//    mbr_check_service_membership -E  -L -S -W -B 200 -C 10 -r 100 -s "SACL" -u user_prefix
53//
54//      libMicro default benchmark run options are "-E -C 200 -L -S -W"
55//
56// -B is batch size: loop iteration per each benchmark run. Needs to match # of
57//                   real lookups. This is total number of lookups to issue.
58// -C is min sample number: how many benchmark needs to run to get proper sample
59//                          1 is mimumum, but you get at least 3 benchmark run
60//                          samples. Do not set to zero. Default is 200 for most
61//                          runs in libMicro.
62// -r is the number of total records.
63// -s is SACL string: ie. "ssh"
64// -u user_prefix that preceeds the user number
65
66typedef struct {
67	uuid_t *uuid_list;
68} tsd_t;
69
70// the number of record lookup to issue is covered by standard option optB
71static int  optRecords =    100;  // the number of total records
72static int  optSACL = 0;          // option SACL specified?
73
74static char **sacl = NULL;
75static char *default_sacl[] = { "com.apple.access_dsproxy",
76                                "com.apple.access_screensharing",
77                                "com.apple.access_ssh",
78                                ""};
79static int  numSACL = 3;          // number of SACLs
80
81
82// This will use local users (local_test_*)
83static char *default_uprefix = "local_test_";
84
85int
86benchmark_init()
87{
88    debug("benchmark_init");
89    (void) sprintf(lm_optstr,  "r:s:u:");
90
91    lm_tsdsize = sizeof(tsd_t);
92    lm_defB = 100;
93
94    (void) sprintf(lm_usage,
95                "\n       ------- mbr_check_service_membership specific options (default: *)\n"
96                "       [-r total number of records (100*)]\n"
97                "       [-s SACL]\n"
98		"	[-u user_prefix]\n"
99                "\n" );
100    return (0);
101}
102
103/*
104 * This is where you parse your lower-case arguments.
105 */
106int
107benchmark_optswitch(int opt, char *optarg)
108{
109    debug("benchmark_optswitch");
110
111    switch (opt) {
112    case 'r':    // total number of records. default is 100
113        optRecords = atoi(optarg);
114        debug("optRecords = %d\n", optRecords);
115        break;
116
117    case 's':    // SACL
118        if (optSACL) {
119            printf("SACL already specified. Skipping");
120            break;
121        }
122        sacl = malloc(2 * sizeof(char *));
123        if (!sacl) {
124            printf("Error: no memory available for strdup\n");
125            return -1;
126        }
127        sacl[0] = strdup(optarg);
128        sacl[1] = "";
129        optSACL = 1;
130        numSACL = 1;
131
132        break;
133
134    case 'u':
135	default_uprefix = strdup(optarg);
136	debug("default_uprefix = %s\n", default_uprefix);
137	break;
138
139    default:
140        return -1;
141    }
142
143    return 0;
144}
145
146
147int
148benchmark_initrun()
149{
150    int i;
151    debug("benchmark_initrun");
152
153    if (!sacl) {
154        sacl = default_sacl;
155    }
156
157    for (i=0; strcmp(sacl[i], "") && i <= numSACL; i++) {
158        debug("SACL = %s", sacl[i]);
159    }
160
161    return (0);
162}
163
164// Initialize all structures that will be used in benchmark()
165// 1. make local or network node for OD query
166// 2. create user key
167int
168benchmark_initworker(void *tsd)
169{
170    int i;
171    tsd_t *ts = (tsd_t *)tsd;
172    char *uprefix = default_uprefix;              // local user is default
173    char username[30] = "";
174    struct passwd *info = NULL;
175
176    debug("benchmark_initworker");
177
178    // create an array of usernames to use in benchmark before their use
179    // realtime generation in benchmark effects performance measurements
180
181    ts->uuid_list = calloc(optRecords, sizeof(uuid_t));
182
183    for (i = 0; i < optRecords; i++) {
184
185        sprintf(username, "%s%d", uprefix, i+1);
186        info = getpwnam(username);
187        if (!info) {
188            debug ("error converting username %s to uuid", username);
189            exit (1);
190        }
191
192        (void) mbr_uid_to_uuid(info->pw_uid, ts->uuid_list[i]);
193
194#if DEBUG
195        char buf[30];
196        uid_t uid;
197        int id_type;
198        uuid_unparse(ts->uuid_list[i], buf);
199        mbr_uuid_to_id(ts->uuid_list[i], &uid, &id_type);
200        debug ("username (%s), uid %d, uuid %s, back to uid %d", username, info->pw_uid, buf, uid);
201#endif
202    }
203
204    // if batch size (one benchmark run) is less than the number records, adjust
205    // it to match the number record lookups in one batch run
206    if (optRecords < lm_optB) {
207        lm_optB = optRecords;
208        debug("Reducing batch size to %d to match the record #\n", lm_optB);
209    }
210
211    debug("benchmark_initworker");
212    return (0);
213}
214
215int
216benchmark(void *tsd, result_t *res)
217{
218    tsd_t *ts = (tsd_t *)tsd;
219    int         i;
220    int         err;
221    int         isMember=0;
222    char        *sacl_chosen;
223
224#ifdef DEBUG
225    uid_t       uid;
226    int         id_type;
227#endif
228
229    res->re_errors = 0;
230
231    debug("in to benchmark - optB = %i", lm_optB);
232    for (i = 0; i < lm_optB; i++) {
233
234        sacl_chosen = sacl[random() % numSACL];
235        err = mbr_check_service_membership(ts->uuid_list[i], sacl_chosen, &isMember);
236
237#ifdef DEBUG
238        mbr_uuid_to_id(ts->uuid_list[i], &uid, &id_type);
239        debug ("loop %d: uid %d is %s a member of %s", i, uid, (isMember) ? "" : "not", sacl_chosen);
240#endif
241
242        if (err) {
243            debug("error: %s", strerror(err));
244            res->re_errors++;
245        }
246    }
247    res->re_count = i;
248
249    return (0);
250}
251
252
253// We need to release all the structures we allocated in benchmark_initworker()
254int
255benchmark_finiworker(void *tsd)
256{
257    tsd_t *ts = (tsd_t *)tsd;
258    debug("benchmark_result: deallocating structures");
259
260    free(ts->uuid_list);
261
262    return (0);
263}
264
265int
266benchmark_finirun(void *tsd)
267{
268	if (optSACL)
269        free(sacl);
270
271	return 0;
272}
273
274char *
275benchmark_result()
276{
277    static char    result = '\0';
278    debug("benchmark_result");
279    return (&result);
280}
281
282