Print this page
4823 don't open-code NSEC2MSEC and MSEC2NSEC
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/idmap/idmapd/dbutils.c
+++ new/usr/src/cmd/idmap/idmapd/dbutils.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23 23 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
24 24 */
25 25
26 26 /*
27 27 * Database related utility routines
28 28 */
29 29
30 30 #include <stdio.h>
31 31 #include <stdlib.h>
32 32 #include <string.h>
33 33 #include <errno.h>
34 34 #include <sys/types.h>
35 35 #include <sys/stat.h>
36 36 #include <rpc/rpc.h>
37 37 #include <sys/sid.h>
38 38 #include <time.h>
39 39 #include <pwd.h>
40 40 #include <grp.h>
41 41 #include <pthread.h>
42 42 #include <assert.h>
43 43 #include <sys/u8_textprep.h>
44 44 #include <alloca.h>
45 45 #include <libuutil.h>
46 46 #include <note.h>
47 47
48 48 #include "idmapd.h"
49 49 #include "adutils.h"
50 50 #include "string.h"
51 51 #include "idmap_priv.h"
52 52 #include "schema.h"
53 53 #include "nldaputils.h"
54 54 #include "idmap_lsa.h"
55 55
56 56
57 57 static idmap_retcode sql_compile_n_step_once(sqlite *, char *,
58 58 sqlite_vm **, int *, int, const char ***);
59 59 static idmap_retcode lookup_localsid2pid(idmap_mapping *, idmap_id_res *);
60 60 static idmap_retcode lookup_cache_name2sid(sqlite *, const char *,
61 61 const char *, char **, char **, idmap_rid_t *, idmap_id_type *);
62 62
63 63 #define EMPTY_NAME(name) (*name == 0 || strcmp(name, "\"\"") == 0)
64 64
65 65 #define DO_NOT_ALLOC_NEW_ID_MAPPING(req)\
66 66 (req->flag & IDMAP_REQ_FLG_NO_NEW_ID_ALLOC)
67 67
68 68 #define AVOID_NAMESERVICE(req)\
69 69 (req->flag & IDMAP_REQ_FLG_NO_NAMESERVICE)
70 70
71 71 #define ALLOW_WK_OR_LOCAL_SIDS_ONLY(req)\
72 72 (req->flag & IDMAP_REQ_FLG_WK_OR_LOCAL_SIDS_ONLY)
73 73
74 74 typedef enum init_db_option {
75 75 FAIL_IF_CORRUPT = 0,
76 76 REMOVE_IF_CORRUPT = 1
77 77 } init_db_option_t;
78 78
79 79 /*
80 80 * Thread specific data to hold the database handles so that the
81 81 * databases are not opened and closed for every request. It also
82 82 * contains the sqlite busy handler structure.
83 83 */
84 84
85 85 struct idmap_busy {
86 86 const char *name;
87 87 const int *delays;
88 88 int delay_size;
89 89 int total;
90 90 int sec;
91 91 };
92 92
93 93
94 94 typedef struct idmap_tsd {
95 95 sqlite *db_db;
96 96 sqlite *cache_db;
97 97 struct idmap_busy cache_busy;
98 98 struct idmap_busy db_busy;
99 99 } idmap_tsd_t;
100 100
101 101 /*
102 102 * Flags to indicate how local the directory we're consulting is.
103 103 * If neither is set, it means the directory belongs to a remote forest.
104 104 */
105 105 #define DOMAIN_IS_LOCAL 0x01
106 106 #define FOREST_IS_LOCAL 0x02
107 107
108 108 static const int cache_delay_table[] =
109 109 { 1, 2, 5, 10, 15, 20, 25, 30, 35, 40,
110 110 50, 50, 60, 70, 80, 90, 100};
111 111
112 112 static const int db_delay_table[] =
113 113 { 5, 10, 15, 20, 30, 40, 55, 70, 100};
114 114
115 115
116 116 static pthread_key_t idmap_tsd_key;
117 117
118 118 void
119 119 idmap_tsd_destroy(void *key)
120 120 {
121 121
122 122 idmap_tsd_t *tsd = (idmap_tsd_t *)key;
123 123 if (tsd) {
124 124 if (tsd->db_db)
125 125 (void) sqlite_close(tsd->db_db);
126 126 if (tsd->cache_db)
127 127 (void) sqlite_close(tsd->cache_db);
128 128 free(tsd);
129 129 }
130 130 }
131 131
132 132 void
133 133 idmap_init_tsd_key(void)
134 134 {
135 135 int rc;
136 136
137 137 rc = pthread_key_create(&idmap_tsd_key, idmap_tsd_destroy);
138 138 assert(rc == 0);
139 139 }
140 140
141 141
142 142
143 143 idmap_tsd_t *
144 144 idmap_get_tsd(void)
145 145 {
146 146 idmap_tsd_t *tsd;
147 147
148 148 if ((tsd = pthread_getspecific(idmap_tsd_key)) == NULL) {
149 149 /* No thread specific data so create it */
150 150 if ((tsd = malloc(sizeof (*tsd))) != NULL) {
151 151 /* Initialize thread specific data */
152 152 (void) memset(tsd, 0, sizeof (*tsd));
153 153 /* save the trhread specific data */
154 154 if (pthread_setspecific(idmap_tsd_key, tsd) != 0) {
155 155 /* Can't store key */
156 156 free(tsd);
157 157 tsd = NULL;
158 158 }
159 159 } else {
160 160 tsd = NULL;
161 161 }
162 162 }
163 163
164 164 return (tsd);
165 165 }
166 166
167 167 /*
168 168 * A simple wrapper around u8_textprep_str() that returns the Unicode
169 169 * lower-case version of some string. The result must be freed.
170 170 */
171 171 char *
172 172 tolower_u8(const char *s)
173 173 {
174 174 char *res = NULL;
175 175 char *outs;
176 176 size_t inlen, outlen, inbytesleft, outbytesleft;
177 177 int rc, err;
178 178
179 179 /*
180 180 * u8_textprep_str() does not allocate memory. The input and
181 181 * output buffers may differ in size (though that would be more
182 182 * likely when normalization is done). We have to loop over it...
183 183 *
184 184 * To improve the chances that we can avoid looping we add 10
185 185 * bytes of output buffer room the first go around.
186 186 */
187 187 inlen = inbytesleft = strlen(s);
188 188 outlen = outbytesleft = inlen + 10;
189 189 if ((res = malloc(outlen)) == NULL)
190 190 return (NULL);
191 191 outs = res;
192 192
193 193 while ((rc = u8_textprep_str((char *)s, &inbytesleft, outs,
194 194 &outbytesleft, U8_TEXTPREP_TOLOWER, U8_UNICODE_LATEST, &err)) < 0 &&
195 195 err == E2BIG) {
196 196 if ((res = realloc(res, outlen + inbytesleft)) == NULL)
197 197 return (NULL);
198 198 /* adjust input/output buffer pointers */
199 199 s += (inlen - inbytesleft);
200 200 outs = res + outlen - outbytesleft;
201 201 /* adjust outbytesleft and outlen */
202 202 outlen += inbytesleft;
203 203 outbytesleft += inbytesleft;
204 204 }
205 205
206 206 if (rc < 0) {
207 207 free(res);
208 208 res = NULL;
209 209 return (NULL);
210 210 }
211 211
212 212 res[outlen - outbytesleft] = '\0';
213 213
214 214 return (res);
215 215 }
216 216
217 217 static int sql_exec_tran_no_cb(sqlite *db, char *sql, const char *dbname,
218 218 const char *while_doing);
219 219
220 220
221 221 /*
222 222 * Initialize 'dbname' using 'sql'
223 223 */
224 224 static
225 225 int
226 226 init_db_instance(const char *dbname, int version,
227 227 const char *detect_version_sql, char * const *sql,
228 228 init_db_option_t opt, int *created, int *upgraded)
229 229 {
230 230 int rc, curr_version;
231 231 int tries = 1;
232 232 int prio = LOG_NOTICE;
233 233 sqlite *db = NULL;
234 234 char *errmsg = NULL;
235 235
236 236 *created = 0;
237 237 *upgraded = 0;
238 238
239 239 if (opt == REMOVE_IF_CORRUPT)
240 240 tries = 3;
241 241
242 242 rinse_repeat:
243 243 if (tries == 0) {
244 244 idmapdlog(LOG_ERR, "Failed to initialize db %s", dbname);
245 245 return (-1);
246 246 }
247 247 if (tries-- == 1)
248 248 /* Last try, log errors */
249 249 prio = LOG_ERR;
250 250
251 251 db = sqlite_open(dbname, 0600, &errmsg);
252 252 if (db == NULL) {
253 253 idmapdlog(prio, "Error creating database %s (%s)",
254 254 dbname, CHECK_NULL(errmsg));
255 255 sqlite_freemem(errmsg);
256 256 if (opt == REMOVE_IF_CORRUPT)
257 257 (void) unlink(dbname);
258 258 goto rinse_repeat;
259 259 }
260 260
261 261 sqlite_busy_timeout(db, 3000);
262 262
263 263 /* Detect current version of schema in the db, if any */
264 264 curr_version = 0;
265 265 if (detect_version_sql != NULL) {
266 266 char *end, **results;
267 267 int nrow;
268 268
269 269 #ifdef IDMAPD_DEBUG
270 270 (void) fprintf(stderr, "Schema version detection SQL: %s\n",
271 271 detect_version_sql);
272 272 #endif /* IDMAPD_DEBUG */
273 273 rc = sqlite_get_table(db, detect_version_sql, &results,
274 274 &nrow, NULL, &errmsg);
275 275 if (rc != SQLITE_OK) {
276 276 idmapdlog(prio,
277 277 "Error detecting schema version of db %s (%s)",
278 278 dbname, errmsg);
279 279 sqlite_freemem(errmsg);
280 280 sqlite_free_table(results);
281 281 sqlite_close(db);
282 282 return (-1);
283 283 }
284 284 if (nrow != 1) {
285 285 idmapdlog(prio,
286 286 "Error detecting schema version of db %s", dbname);
287 287 sqlite_close(db);
288 288 sqlite_free_table(results);
289 289 return (-1);
290 290 }
291 291 curr_version = strtol(results[1], &end, 10);
292 292 sqlite_free_table(results);
293 293 }
294 294
295 295 if (curr_version < 0) {
296 296 if (opt == REMOVE_IF_CORRUPT)
297 297 (void) unlink(dbname);
298 298 goto rinse_repeat;
299 299 }
300 300
301 301 if (curr_version == version)
302 302 goto done;
303 303
304 304 /* Install or upgrade schema */
305 305 #ifdef IDMAPD_DEBUG
306 306 (void) fprintf(stderr, "Schema init/upgrade SQL: %s\n",
307 307 sql[curr_version]);
308 308 #endif /* IDMAPD_DEBUG */
309 309 rc = sql_exec_tran_no_cb(db, sql[curr_version], dbname,
310 310 (curr_version == 0) ? "installing schema" : "upgrading schema");
311 311 if (rc != 0) {
312 312 idmapdlog(prio, "Error %s schema for db %s", dbname,
313 313 (curr_version == 0) ? "installing schema" :
314 314 "upgrading schema");
315 315 if (opt == REMOVE_IF_CORRUPT)
316 316 (void) unlink(dbname);
317 317 goto rinse_repeat;
318 318 }
319 319
320 320 *upgraded = (curr_version > 0);
321 321 *created = (curr_version == 0);
322 322
323 323 done:
324 324 (void) sqlite_close(db);
325 325 return (0);
326 326 }
327 327
328 328
329 329 /*
330 330 * This is the SQLite database busy handler that retries the SQL
331 331 * operation until it is successful.
332 332 */
333 333 int
334 334 /* LINTED E_FUNC_ARG_UNUSED */
335 335 idmap_sqlite_busy_handler(void *arg, const char *table_name, int count)
336 336 {
337 337 struct idmap_busy *busy = arg;
338 338 int delay;
339 339 struct timespec rqtp;
340 340
341 341 if (count == 1) {
342 342 busy->total = 0;
343 343 busy->sec = 2;
344 344 }
345 345 if (busy->total > 1000 * busy->sec) {
346 346 idmapdlog(LOG_DEBUG,
347 347 "Thread %d waited %d sec for the %s database",
348 348 pthread_self(), busy->sec, busy->name);
↓ open down ↓ |
348 lines elided |
↑ open up ↑ |
349 349 busy->sec++;
350 350 }
351 351
352 352 if (count <= busy->delay_size) {
353 353 delay = busy->delays[count-1];
354 354 } else {
355 355 delay = busy->delays[busy->delay_size - 1];
356 356 }
357 357 busy->total += delay;
358 358 rqtp.tv_sec = 0;
359 - rqtp.tv_nsec = delay * (NANOSEC / MILLISEC);
359 + rqtp.tv_nsec = MSEC2NSEC(delay);
360 360 (void) nanosleep(&rqtp, NULL);
361 361 return (1);
362 362 }
363 363
364 364
365 365 /*
366 366 * Get the database handle
367 367 */
368 368 idmap_retcode
369 369 get_db_handle(sqlite **db)
370 370 {
371 371 char *errmsg;
372 372 idmap_tsd_t *tsd;
373 373
374 374 /*
375 375 * Retrieve the db handle from thread-specific storage
376 376 * If none exists, open and store in thread-specific storage.
377 377 */
378 378 if ((tsd = idmap_get_tsd()) == NULL) {
379 379 idmapdlog(LOG_ERR,
380 380 "Error getting thread specific data for %s", IDMAP_DBNAME);
381 381 return (IDMAP_ERR_MEMORY);
382 382 }
383 383
384 384 if (tsd->db_db == NULL) {
385 385 tsd->db_db = sqlite_open(IDMAP_DBNAME, 0, &errmsg);
386 386 if (tsd->db_db == NULL) {
387 387 idmapdlog(LOG_ERR, "Error opening database %s (%s)",
388 388 IDMAP_DBNAME, CHECK_NULL(errmsg));
389 389 sqlite_freemem(errmsg);
390 390 return (IDMAP_ERR_DB);
391 391 }
392 392
393 393 tsd->db_busy.name = IDMAP_DBNAME;
394 394 tsd->db_busy.delays = db_delay_table;
395 395 tsd->db_busy.delay_size = sizeof (db_delay_table) /
396 396 sizeof (int);
397 397 sqlite_busy_handler(tsd->db_db, idmap_sqlite_busy_handler,
398 398 &tsd->db_busy);
399 399 }
400 400 *db = tsd->db_db;
401 401 return (IDMAP_SUCCESS);
402 402 }
403 403
404 404 /*
405 405 * Get the cache handle
406 406 */
407 407 idmap_retcode
408 408 get_cache_handle(sqlite **cache)
409 409 {
410 410 char *errmsg;
411 411 idmap_tsd_t *tsd;
412 412
413 413 /*
414 414 * Retrieve the db handle from thread-specific storage
415 415 * If none exists, open and store in thread-specific storage.
416 416 */
417 417 if ((tsd = idmap_get_tsd()) == NULL) {
418 418 idmapdlog(LOG_ERR, "Error getting thread specific data for %s",
419 419 IDMAP_DBNAME);
420 420 return (IDMAP_ERR_MEMORY);
421 421 }
422 422
423 423 if (tsd->cache_db == NULL) {
424 424 tsd->cache_db = sqlite_open(IDMAP_CACHENAME, 0, &errmsg);
425 425 if (tsd->cache_db == NULL) {
426 426 idmapdlog(LOG_ERR, "Error opening database %s (%s)",
427 427 IDMAP_CACHENAME, CHECK_NULL(errmsg));
428 428 sqlite_freemem(errmsg);
429 429 return (IDMAP_ERR_DB);
430 430 }
431 431
432 432 tsd->cache_busy.name = IDMAP_CACHENAME;
433 433 tsd->cache_busy.delays = cache_delay_table;
434 434 tsd->cache_busy.delay_size = sizeof (cache_delay_table) /
435 435 sizeof (int);
436 436 sqlite_busy_handler(tsd->cache_db, idmap_sqlite_busy_handler,
437 437 &tsd->cache_busy);
438 438 }
439 439 *cache = tsd->cache_db;
440 440 return (IDMAP_SUCCESS);
441 441 }
442 442
443 443 /*
444 444 * Initialize cache and db
445 445 */
446 446 int
447 447 init_dbs()
448 448 {
449 449 char *sql[4];
450 450 int created, upgraded;
451 451
452 452 /* name-based mappings; probably OK to blow away in a pinch(?) */
453 453 sql[0] = DB_INSTALL_SQL;
454 454 sql[1] = DB_UPGRADE_FROM_v1_SQL;
455 455 sql[2] = NULL;
456 456
457 457 if (init_db_instance(IDMAP_DBNAME, DB_VERSION, DB_VERSION_SQL, sql,
458 458 FAIL_IF_CORRUPT, &created, &upgraded) < 0)
459 459 return (-1);
460 460
461 461 /* mappings, name/SID lookup cache + ephemeral IDs; OK to blow away */
462 462 sql[0] = CACHE_INSTALL_SQL;
463 463 sql[1] = CACHE_UPGRADE_FROM_v1_SQL;
464 464 sql[2] = CACHE_UPGRADE_FROM_v2_SQL;
465 465 sql[3] = NULL;
466 466
467 467 if (init_db_instance(IDMAP_CACHENAME, CACHE_VERSION, CACHE_VERSION_SQL,
468 468 sql, REMOVE_IF_CORRUPT, &created, &upgraded) < 0)
469 469 return (-1);
470 470
471 471 _idmapdstate.new_eph_db = (created || upgraded) ? 1 : 0;
472 472
473 473 return (0);
474 474 }
475 475
476 476 /*
477 477 * Finalize databases
478 478 */
479 479 void
480 480 fini_dbs()
481 481 {
482 482 }
483 483
484 484 /*
485 485 * This table is a listing of status codes that will be returned to the
486 486 * client when a SQL command fails with the corresponding error message.
487 487 */
488 488 static msg_table_t sqlmsgtable[] = {
489 489 {IDMAP_ERR_U2W_NAMERULE_CONFLICT,
490 490 "columns unixname, is_user, u2w_order are not unique"},
491 491 {IDMAP_ERR_W2U_NAMERULE_CONFLICT,
492 492 "columns winname, windomain, is_user, is_wuser, w2u_order are not"
493 493 " unique"},
494 494 {IDMAP_ERR_W2U_NAMERULE_CONFLICT, "Conflicting w2u namerules"},
495 495 {-1, NULL}
496 496 };
497 497
498 498 /*
499 499 * idmapd's version of string2stat to map SQLite messages to
500 500 * status codes
501 501 */
502 502 idmap_retcode
503 503 idmapd_string2stat(const char *msg)
504 504 {
505 505 int i;
506 506 for (i = 0; sqlmsgtable[i].msg; i++) {
507 507 if (strcasecmp(sqlmsgtable[i].msg, msg) == 0)
508 508 return (sqlmsgtable[i].retcode);
509 509 }
510 510 return (IDMAP_ERR_OTHER);
511 511 }
512 512
513 513 /*
514 514 * Executes some SQL in a transaction.
515 515 *
516 516 * Returns 0 on success, -1 if it failed but the rollback succeeded, -2
517 517 * if the rollback failed.
518 518 */
519 519 static
520 520 int
521 521 sql_exec_tran_no_cb(sqlite *db, char *sql, const char *dbname,
522 522 const char *while_doing)
523 523 {
524 524 char *errmsg = NULL;
525 525 int rc;
526 526
527 527 rc = sqlite_exec(db, "BEGIN TRANSACTION;", NULL, NULL, &errmsg);
528 528 if (rc != SQLITE_OK) {
529 529 idmapdlog(LOG_ERR, "Begin transaction failed (%s) "
530 530 "while %s (%s)", errmsg, while_doing, dbname);
531 531 sqlite_freemem(errmsg);
532 532 return (-1);
533 533 }
534 534
535 535 rc = sqlite_exec(db, sql, NULL, NULL, &errmsg);
536 536 if (rc != SQLITE_OK) {
537 537 idmapdlog(LOG_ERR, "Database error (%s) while %s (%s)", errmsg,
538 538 while_doing, dbname);
539 539 sqlite_freemem(errmsg);
540 540 errmsg = NULL;
541 541 goto rollback;
542 542 }
543 543
544 544 rc = sqlite_exec(db, "COMMIT TRANSACTION", NULL, NULL, &errmsg);
545 545 if (rc == SQLITE_OK) {
546 546 sqlite_freemem(errmsg);
547 547 return (0);
548 548 }
549 549
550 550 idmapdlog(LOG_ERR, "Database commit error (%s) while s (%s)",
551 551 errmsg, while_doing, dbname);
552 552 sqlite_freemem(errmsg);
553 553 errmsg = NULL;
554 554
555 555 rollback:
556 556 rc = sqlite_exec(db, "ROLLBACK TRANSACTION", NULL, NULL, &errmsg);
557 557 if (rc != SQLITE_OK) {
558 558 idmapdlog(LOG_ERR, "Rollback failed (%s) while %s (%s)",
559 559 errmsg, while_doing, dbname);
560 560 sqlite_freemem(errmsg);
561 561 return (-2);
562 562 }
563 563 sqlite_freemem(errmsg);
564 564
565 565 return (-1);
566 566 }
567 567
568 568 /*
569 569 * Execute the given SQL statment without using any callbacks
570 570 */
571 571 idmap_retcode
572 572 sql_exec_no_cb(sqlite *db, const char *dbname, char *sql)
573 573 {
574 574 char *errmsg = NULL;
575 575 int r;
576 576 idmap_retcode retcode;
577 577
578 578 r = sqlite_exec(db, sql, NULL, NULL, &errmsg);
579 579 assert(r != SQLITE_LOCKED && r != SQLITE_BUSY);
580 580
581 581 if (r != SQLITE_OK) {
582 582 idmapdlog(LOG_ERR, "Database error on %s while executing %s "
583 583 "(%s)", dbname, sql, CHECK_NULL(errmsg));
584 584 retcode = idmapd_string2stat(errmsg);
585 585 if (errmsg != NULL)
586 586 sqlite_freemem(errmsg);
587 587 return (retcode);
588 588 }
589 589
590 590 return (IDMAP_SUCCESS);
591 591 }
592 592
593 593 /*
594 594 * Generate expression that can be used in WHERE statements.
595 595 * Examples:
596 596 * <prefix> <col> <op> <value> <suffix>
597 597 * "" "unixuser" "=" "foo" "AND"
598 598 */
599 599 idmap_retcode
600 600 gen_sql_expr_from_rule(idmap_namerule *rule, char **out)
601 601 {
602 602 char *s_windomain = NULL, *s_winname = NULL;
603 603 char *s_unixname = NULL;
604 604 char *dir;
605 605 char *lower_winname;
606 606 int retcode = IDMAP_SUCCESS;
607 607
608 608 if (out == NULL)
609 609 return (IDMAP_ERR_ARG);
610 610
611 611
612 612 if (!EMPTY_STRING(rule->windomain)) {
613 613 s_windomain = sqlite_mprintf("AND windomain = %Q ",
614 614 rule->windomain);
615 615 if (s_windomain == NULL) {
616 616 retcode = IDMAP_ERR_MEMORY;
617 617 goto out;
618 618 }
619 619 }
620 620
621 621 if (!EMPTY_STRING(rule->winname)) {
622 622 if ((lower_winname = tolower_u8(rule->winname)) == NULL)
623 623 lower_winname = rule->winname;
624 624 s_winname = sqlite_mprintf(
625 625 "AND winname = %Q AND is_wuser = %d ",
626 626 lower_winname, rule->is_wuser ? 1 : 0);
627 627 if (lower_winname != rule->winname)
628 628 free(lower_winname);
629 629 if (s_winname == NULL) {
630 630 retcode = IDMAP_ERR_MEMORY;
631 631 goto out;
632 632 }
633 633 }
634 634
635 635 if (!EMPTY_STRING(rule->unixname)) {
636 636 s_unixname = sqlite_mprintf(
637 637 "AND unixname = %Q AND is_user = %d ",
638 638 rule->unixname, rule->is_user ? 1 : 0);
639 639 if (s_unixname == NULL) {
640 640 retcode = IDMAP_ERR_MEMORY;
641 641 goto out;
642 642 }
643 643 }
644 644
645 645 switch (rule->direction) {
646 646 case IDMAP_DIRECTION_BI:
647 647 dir = "AND w2u_order > 0 AND u2w_order > 0";
648 648 break;
649 649 case IDMAP_DIRECTION_W2U:
650 650 dir = "AND w2u_order > 0"
651 651 " AND (u2w_order = 0 OR u2w_order ISNULL)";
652 652 break;
653 653 case IDMAP_DIRECTION_U2W:
654 654 dir = "AND u2w_order > 0"
655 655 " AND (w2u_order = 0 OR w2u_order ISNULL)";
656 656 break;
657 657 default:
658 658 dir = "";
659 659 break;
660 660 }
661 661
662 662 *out = sqlite_mprintf("%s %s %s %s",
663 663 s_windomain ? s_windomain : "",
664 664 s_winname ? s_winname : "",
665 665 s_unixname ? s_unixname : "",
666 666 dir);
667 667
668 668 if (*out == NULL) {
669 669 retcode = IDMAP_ERR_MEMORY;
670 670 idmapdlog(LOG_ERR, "Out of memory");
671 671 goto out;
672 672 }
673 673
674 674 out:
675 675 if (s_windomain != NULL)
676 676 sqlite_freemem(s_windomain);
677 677 if (s_winname != NULL)
678 678 sqlite_freemem(s_winname);
679 679 if (s_unixname != NULL)
680 680 sqlite_freemem(s_unixname);
681 681
682 682 return (retcode);
683 683 }
684 684
685 685
686 686
687 687 /*
688 688 * Generate and execute SQL statement for LIST RPC calls
689 689 */
690 690 idmap_retcode
691 691 process_list_svc_sql(sqlite *db, const char *dbname, char *sql, uint64_t limit,
692 692 int flag, list_svc_cb cb, void *result)
693 693 {
694 694 list_cb_data_t cb_data;
695 695 char *errmsg = NULL;
696 696 int r;
697 697 idmap_retcode retcode = IDMAP_ERR_INTERNAL;
698 698
699 699 (void) memset(&cb_data, 0, sizeof (cb_data));
700 700 cb_data.result = result;
701 701 cb_data.limit = limit;
702 702 cb_data.flag = flag;
703 703
704 704
705 705 r = sqlite_exec(db, sql, cb, &cb_data, &errmsg);
706 706 assert(r != SQLITE_LOCKED && r != SQLITE_BUSY);
707 707 switch (r) {
708 708 case SQLITE_OK:
709 709 retcode = IDMAP_SUCCESS;
710 710 break;
711 711
712 712 default:
713 713 retcode = IDMAP_ERR_INTERNAL;
714 714 idmapdlog(LOG_ERR, "Database error on %s while executing "
715 715 "%s (%s)", dbname, sql, CHECK_NULL(errmsg));
716 716 break;
717 717 }
718 718 if (errmsg != NULL)
719 719 sqlite_freemem(errmsg);
720 720 return (retcode);
721 721 }
722 722
723 723 /*
724 724 * This routine is called by callbacks that process the results of
725 725 * LIST RPC calls to validate data and to allocate memory for
726 726 * the result array.
727 727 */
728 728 idmap_retcode
729 729 validate_list_cb_data(list_cb_data_t *cb_data, int argc, char **argv,
730 730 int ncol, uchar_t **list, size_t valsize)
731 731 {
732 732 size_t nsize;
733 733 void *tmplist;
734 734
735 735 if (cb_data->limit > 0 && cb_data->next == cb_data->limit)
736 736 return (IDMAP_NEXT);
737 737
738 738 if (argc < ncol || argv == NULL) {
739 739 idmapdlog(LOG_ERR, "Invalid data");
740 740 return (IDMAP_ERR_INTERNAL);
741 741 }
742 742
743 743 /* alloc in bulk to reduce number of reallocs */
744 744 if (cb_data->next >= cb_data->len) {
745 745 nsize = (cb_data->len + SIZE_INCR) * valsize;
746 746 tmplist = realloc(*list, nsize);
747 747 if (tmplist == NULL) {
748 748 idmapdlog(LOG_ERR, "Out of memory");
749 749 return (IDMAP_ERR_MEMORY);
750 750 }
751 751 *list = tmplist;
752 752 (void) memset(*list + (cb_data->len * valsize), 0,
753 753 SIZE_INCR * valsize);
754 754 cb_data->len += SIZE_INCR;
755 755 }
756 756 return (IDMAP_SUCCESS);
757 757 }
758 758
759 759 static
760 760 idmap_retcode
761 761 get_namerule_order(char *winname, char *windomain, char *unixname,
762 762 int direction, int is_diagonal, int *w2u_order, int *u2w_order)
763 763 {
764 764 *w2u_order = 0;
765 765 *u2w_order = 0;
766 766
767 767 /*
768 768 * Windows to UNIX lookup order:
769 769 * 1. winname@domain (or winname) to ""
770 770 * 2. winname@domain (or winname) to unixname
771 771 * 3. winname@* to ""
772 772 * 4. winname@* to unixname
773 773 * 5. *@domain (or *) to *
774 774 * 6. *@domain (or *) to ""
775 775 * 7. *@domain (or *) to unixname
776 776 * 8. *@* to *
777 777 * 9. *@* to ""
778 778 * 10. *@* to unixname
779 779 *
780 780 * winname is a special case of winname@domain when domain is the
781 781 * default domain. Similarly * is a special case of *@domain when
782 782 * domain is the default domain.
783 783 *
784 784 * Note that "" has priority over specific names because "" inhibits
785 785 * mappings and traditionally deny rules always had higher priority.
786 786 */
787 787 if (direction != IDMAP_DIRECTION_U2W) {
788 788 /* bi-directional or from windows to unix */
789 789 if (winname == NULL)
790 790 return (IDMAP_ERR_W2U_NAMERULE);
791 791 else if (unixname == NULL)
792 792 return (IDMAP_ERR_W2U_NAMERULE);
793 793 else if (EMPTY_NAME(winname))
794 794 return (IDMAP_ERR_W2U_NAMERULE);
795 795 else if (*winname == '*' && windomain && *windomain == '*') {
796 796 if (*unixname == '*')
797 797 *w2u_order = 8;
798 798 else if (EMPTY_NAME(unixname))
799 799 *w2u_order = 9;
800 800 else /* unixname == name */
801 801 *w2u_order = 10;
802 802 } else if (*winname == '*') {
803 803 if (*unixname == '*')
804 804 *w2u_order = 5;
805 805 else if (EMPTY_NAME(unixname))
806 806 *w2u_order = 6;
807 807 else /* name */
808 808 *w2u_order = 7;
809 809 } else if (windomain != NULL && *windomain == '*') {
810 810 /* winname == name */
811 811 if (*unixname == '*')
812 812 return (IDMAP_ERR_W2U_NAMERULE);
813 813 else if (EMPTY_NAME(unixname))
814 814 *w2u_order = 3;
815 815 else /* name */
816 816 *w2u_order = 4;
817 817 } else {
818 818 /* winname == name && windomain == null or name */
819 819 if (*unixname == '*')
820 820 return (IDMAP_ERR_W2U_NAMERULE);
821 821 else if (EMPTY_NAME(unixname))
822 822 *w2u_order = 1;
823 823 else /* name */
824 824 *w2u_order = 2;
825 825 }
826 826
827 827 }
828 828
829 829 /*
830 830 * 1. unixname to "", non-diagonal
831 831 * 2. unixname to winname@domain (or winname), non-diagonal
832 832 * 3. unixname to "", diagonal
833 833 * 4. unixname to winname@domain (or winname), diagonal
834 834 * 5. * to *@domain (or *), non-diagonal
835 835 * 5. * to *@domain (or *), diagonal
836 836 * 7. * to ""
837 837 * 8. * to winname@domain (or winname)
838 838 * 9. * to "", non-diagonal
839 839 * 10. * to winname@domain (or winname), diagonal
840 840 */
841 841 if (direction != IDMAP_DIRECTION_W2U) {
842 842 int diagonal = is_diagonal ? 1 : 0;
843 843
844 844 /* bi-directional or from unix to windows */
845 845 if (unixname == NULL || EMPTY_NAME(unixname))
846 846 return (IDMAP_ERR_U2W_NAMERULE);
847 847 else if (winname == NULL)
848 848 return (IDMAP_ERR_U2W_NAMERULE);
849 849 else if (windomain != NULL && *windomain == '*')
850 850 return (IDMAP_ERR_U2W_NAMERULE);
851 851 else if (*unixname == '*') {
852 852 if (*winname == '*')
853 853 *u2w_order = 5 + diagonal;
854 854 else if (EMPTY_NAME(winname))
855 855 *u2w_order = 7 + 2 * diagonal;
856 856 else
857 857 *u2w_order = 8 + 2 * diagonal;
858 858 } else {
859 859 if (*winname == '*')
860 860 return (IDMAP_ERR_U2W_NAMERULE);
861 861 else if (EMPTY_NAME(winname))
862 862 *u2w_order = 1 + 2 * diagonal;
863 863 else
864 864 *u2w_order = 2 + 2 * diagonal;
865 865 }
866 866 }
867 867 return (IDMAP_SUCCESS);
868 868 }
869 869
870 870 /*
871 871 * Generate and execute SQL statement to add name-based mapping rule
872 872 */
873 873 idmap_retcode
874 874 add_namerule(sqlite *db, idmap_namerule *rule)
875 875 {
876 876 char *sql = NULL;
877 877 idmap_stat retcode;
878 878 char *dom = NULL;
879 879 char *name;
880 880 int w2u_order, u2w_order;
881 881 char w2ubuf[11], u2wbuf[11];
882 882 char *canonname = NULL;
883 883 char *canondomain = NULL;
884 884
885 885 retcode = get_namerule_order(rule->winname, rule->windomain,
886 886 rule->unixname, rule->direction,
887 887 rule->is_user == rule->is_wuser ? 0 : 1, &w2u_order, &u2w_order);
888 888 if (retcode != IDMAP_SUCCESS)
889 889 goto out;
890 890
891 891 if (w2u_order)
892 892 (void) snprintf(w2ubuf, sizeof (w2ubuf), "%d", w2u_order);
893 893 if (u2w_order)
894 894 (void) snprintf(u2wbuf, sizeof (u2wbuf), "%d", u2w_order);
895 895
896 896 /*
897 897 * For the triggers on namerules table to work correctly:
898 898 * 1) Use NULL instead of 0 for w2u_order and u2w_order
899 899 * 2) Use "" instead of NULL for "no domain"
900 900 */
901 901
902 902 name = rule->winname;
903 903 dom = rule->windomain;
904 904
905 905 RDLOCK_CONFIG();
906 906 if (lookup_wksids_name2sid(name, dom,
907 907 &canonname, &canondomain,
908 908 NULL, NULL, NULL) == IDMAP_SUCCESS) {
909 909 name = canonname;
910 910 dom = canondomain;
911 911 } else if (EMPTY_STRING(dom)) {
912 912 if (_idmapdstate.cfg->pgcfg.default_domain)
913 913 dom = _idmapdstate.cfg->pgcfg.default_domain;
914 914 else
915 915 dom = "";
916 916 }
917 917 sql = sqlite_mprintf("INSERT into namerules "
918 918 "(is_user, is_wuser, windomain, winname_display, is_nt4, "
919 919 "unixname, w2u_order, u2w_order) "
920 920 "VALUES(%d, %d, %Q, %Q, %d, %Q, %q, %q);",
921 921 rule->is_user ? 1 : 0, rule->is_wuser ? 1 : 0, dom,
922 922 name, rule->is_nt4 ? 1 : 0, rule->unixname,
923 923 w2u_order ? w2ubuf : NULL, u2w_order ? u2wbuf : NULL);
924 924 UNLOCK_CONFIG();
925 925
926 926 if (sql == NULL) {
927 927 retcode = IDMAP_ERR_INTERNAL;
928 928 idmapdlog(LOG_ERR, "Out of memory");
929 929 goto out;
930 930 }
931 931
932 932 retcode = sql_exec_no_cb(db, IDMAP_DBNAME, sql);
933 933
934 934 if (retcode == IDMAP_ERR_OTHER)
935 935 retcode = IDMAP_ERR_CFG;
936 936
937 937 out:
938 938 free(canonname);
939 939 free(canondomain);
940 940 if (sql != NULL)
941 941 sqlite_freemem(sql);
942 942 return (retcode);
943 943 }
944 944
945 945 /*
946 946 * Flush name-based mapping rules
947 947 */
948 948 idmap_retcode
949 949 flush_namerules(sqlite *db)
950 950 {
951 951 idmap_stat retcode;
952 952
953 953 retcode = sql_exec_no_cb(db, IDMAP_DBNAME, "DELETE FROM namerules;");
954 954
955 955 return (retcode);
956 956 }
957 957
958 958 /*
959 959 * Generate and execute SQL statement to remove a name-based mapping rule
960 960 */
961 961 idmap_retcode
962 962 rm_namerule(sqlite *db, idmap_namerule *rule)
963 963 {
964 964 char *sql = NULL;
965 965 idmap_stat retcode;
966 966 char *expr = NULL;
967 967
968 968 if (rule->direction < 0 && EMPTY_STRING(rule->windomain) &&
969 969 EMPTY_STRING(rule->winname) && EMPTY_STRING(rule->unixname))
970 970 return (IDMAP_SUCCESS);
971 971
972 972 retcode = gen_sql_expr_from_rule(rule, &expr);
973 973 if (retcode != IDMAP_SUCCESS)
974 974 goto out;
975 975
976 976 sql = sqlite_mprintf("DELETE FROM namerules WHERE 1 %s;", expr);
977 977
978 978 if (sql == NULL) {
979 979 retcode = IDMAP_ERR_INTERNAL;
980 980 idmapdlog(LOG_ERR, "Out of memory");
981 981 goto out;
982 982 }
983 983
984 984
985 985 retcode = sql_exec_no_cb(db, IDMAP_DBNAME, sql);
986 986
987 987 out:
988 988 if (expr != NULL)
989 989 sqlite_freemem(expr);
990 990 if (sql != NULL)
991 991 sqlite_freemem(sql);
992 992 return (retcode);
993 993 }
994 994
995 995 /*
996 996 * Compile the given SQL query and step just once.
997 997 *
998 998 * Input:
999 999 * db - db handle
1000 1000 * sql - SQL statement
1001 1001 *
1002 1002 * Output:
1003 1003 * vm - virtual SQL machine
1004 1004 * ncol - number of columns in the result
1005 1005 * values - column values
1006 1006 *
1007 1007 * Return values:
1008 1008 * IDMAP_SUCCESS
1009 1009 * IDMAP_ERR_NOTFOUND
1010 1010 * IDMAP_ERR_INTERNAL
1011 1011 */
1012 1012
1013 1013 static
1014 1014 idmap_retcode
1015 1015 sql_compile_n_step_once(sqlite *db, char *sql, sqlite_vm **vm, int *ncol,
1016 1016 int reqcol, const char ***values)
1017 1017 {
1018 1018 char *errmsg = NULL;
1019 1019 int r;
1020 1020
1021 1021 if ((r = sqlite_compile(db, sql, NULL, vm, &errmsg)) != SQLITE_OK) {
1022 1022 idmapdlog(LOG_ERR, "Database error during %s (%s)", sql,
1023 1023 CHECK_NULL(errmsg));
1024 1024 sqlite_freemem(errmsg);
1025 1025 return (IDMAP_ERR_INTERNAL);
1026 1026 }
1027 1027
1028 1028 r = sqlite_step(*vm, ncol, values, NULL);
1029 1029 assert(r != SQLITE_LOCKED && r != SQLITE_BUSY);
1030 1030
1031 1031 if (r == SQLITE_ROW) {
1032 1032 if (ncol != NULL && *ncol < reqcol) {
1033 1033 (void) sqlite_finalize(*vm, NULL);
1034 1034 *vm = NULL;
1035 1035 return (IDMAP_ERR_INTERNAL);
1036 1036 }
1037 1037 /* Caller will call finalize after using the results */
1038 1038 return (IDMAP_SUCCESS);
1039 1039 } else if (r == SQLITE_DONE) {
1040 1040 (void) sqlite_finalize(*vm, NULL);
1041 1041 *vm = NULL;
1042 1042 return (IDMAP_ERR_NOTFOUND);
1043 1043 }
1044 1044
1045 1045 (void) sqlite_finalize(*vm, &errmsg);
1046 1046 *vm = NULL;
1047 1047 idmapdlog(LOG_ERR, "Database error during %s (%s)", sql,
1048 1048 CHECK_NULL(errmsg));
1049 1049 sqlite_freemem(errmsg);
1050 1050 return (IDMAP_ERR_INTERNAL);
1051 1051 }
1052 1052
1053 1053 /*
1054 1054 * Load config in the state.
1055 1055 *
1056 1056 * nm_siduid and nm_sidgid fields:
1057 1057 * state->nm_siduid represents mode used by sid2uid and uid2sid
1058 1058 * requests for directory-based name mappings. Similarly,
1059 1059 * state->nm_sidgid represents mode used by sid2gid and gid2sid
1060 1060 * requests.
1061 1061 *
1062 1062 * sid2uid/uid2sid:
1063 1063 * none -> directory_based_mapping != DIRECTORY_MAPPING_NAME
1064 1064 * AD-mode -> !nldap_winname_attr && ad_unixuser_attr
1065 1065 * nldap-mode -> nldap_winname_attr && !ad_unixuser_attr
1066 1066 * mixed-mode -> nldap_winname_attr && ad_unixuser_attr
1067 1067 *
1068 1068 * sid2gid/gid2sid:
1069 1069 * none -> directory_based_mapping != DIRECTORY_MAPPING_NAME
1070 1070 * AD-mode -> !nldap_winname_attr && ad_unixgroup_attr
1071 1071 * nldap-mode -> nldap_winname_attr && !ad_unixgroup_attr
1072 1072 * mixed-mode -> nldap_winname_attr && ad_unixgroup_attr
1073 1073 */
1074 1074 idmap_retcode
1075 1075 load_cfg_in_state(lookup_state_t *state)
1076 1076 {
1077 1077 state->nm_siduid = IDMAP_NM_NONE;
1078 1078 state->nm_sidgid = IDMAP_NM_NONE;
1079 1079 RDLOCK_CONFIG();
1080 1080
1081 1081 state->eph_map_unres_sids = 0;
1082 1082 if (_idmapdstate.cfg->pgcfg.eph_map_unres_sids)
1083 1083 state->eph_map_unres_sids = 1;
1084 1084
1085 1085 state->id_cache_timeout =
1086 1086 _idmapdstate.cfg->pgcfg.id_cache_timeout;
1087 1087 state->name_cache_timeout =
1088 1088 _idmapdstate.cfg->pgcfg.name_cache_timeout;
1089 1089
1090 1090 state->directory_based_mapping =
1091 1091 _idmapdstate.cfg->pgcfg.directory_based_mapping;
1092 1092
1093 1093 if (_idmapdstate.cfg->pgcfg.default_domain != NULL) {
1094 1094 state->defdom =
1095 1095 strdup(_idmapdstate.cfg->pgcfg.default_domain);
1096 1096 if (state->defdom == NULL) {
1097 1097 UNLOCK_CONFIG();
1098 1098 return (IDMAP_ERR_MEMORY);
1099 1099 }
1100 1100 } else {
1101 1101 UNLOCK_CONFIG();
1102 1102 return (IDMAP_SUCCESS);
1103 1103 }
1104 1104
1105 1105 if (_idmapdstate.cfg->pgcfg.directory_based_mapping !=
1106 1106 DIRECTORY_MAPPING_NAME) {
1107 1107 UNLOCK_CONFIG();
1108 1108 return (IDMAP_SUCCESS);
1109 1109 }
1110 1110
1111 1111 if (_idmapdstate.cfg->pgcfg.nldap_winname_attr != NULL) {
1112 1112 state->nm_siduid =
1113 1113 (_idmapdstate.cfg->pgcfg.ad_unixuser_attr != NULL)
1114 1114 ? IDMAP_NM_MIXED : IDMAP_NM_NLDAP;
1115 1115 state->nm_sidgid =
1116 1116 (_idmapdstate.cfg->pgcfg.ad_unixgroup_attr != NULL)
1117 1117 ? IDMAP_NM_MIXED : IDMAP_NM_NLDAP;
1118 1118 } else {
1119 1119 state->nm_siduid =
1120 1120 (_idmapdstate.cfg->pgcfg.ad_unixuser_attr != NULL)
1121 1121 ? IDMAP_NM_AD : IDMAP_NM_NONE;
1122 1122 state->nm_sidgid =
1123 1123 (_idmapdstate.cfg->pgcfg.ad_unixgroup_attr != NULL)
1124 1124 ? IDMAP_NM_AD : IDMAP_NM_NONE;
1125 1125 }
1126 1126 if (_idmapdstate.cfg->pgcfg.ad_unixuser_attr != NULL) {
1127 1127 state->ad_unixuser_attr =
1128 1128 strdup(_idmapdstate.cfg->pgcfg.ad_unixuser_attr);
1129 1129 if (state->ad_unixuser_attr == NULL) {
1130 1130 UNLOCK_CONFIG();
1131 1131 return (IDMAP_ERR_MEMORY);
1132 1132 }
1133 1133 }
1134 1134 if (_idmapdstate.cfg->pgcfg.ad_unixgroup_attr != NULL) {
1135 1135 state->ad_unixgroup_attr =
1136 1136 strdup(_idmapdstate.cfg->pgcfg.ad_unixgroup_attr);
1137 1137 if (state->ad_unixgroup_attr == NULL) {
1138 1138 UNLOCK_CONFIG();
1139 1139 return (IDMAP_ERR_MEMORY);
1140 1140 }
1141 1141 }
1142 1142 if (_idmapdstate.cfg->pgcfg.nldap_winname_attr != NULL) {
1143 1143 state->nldap_winname_attr =
1144 1144 strdup(_idmapdstate.cfg->pgcfg.nldap_winname_attr);
1145 1145 if (state->nldap_winname_attr == NULL) {
1146 1146 UNLOCK_CONFIG();
1147 1147 return (IDMAP_ERR_MEMORY);
1148 1148 }
1149 1149 }
1150 1150 UNLOCK_CONFIG();
1151 1151 return (IDMAP_SUCCESS);
1152 1152 }
1153 1153
1154 1154 /*
1155 1155 * Set the rule with specified values.
1156 1156 * All the strings are copied.
1157 1157 */
1158 1158 static void
1159 1159 idmap_namerule_set(idmap_namerule *rule, const char *windomain,
1160 1160 const char *winname, const char *unixname, boolean_t is_user,
1161 1161 boolean_t is_wuser, boolean_t is_nt4, int direction)
1162 1162 {
1163 1163 /*
1164 1164 * Only update if they differ because we have to free
1165 1165 * and duplicate the strings
1166 1166 */
1167 1167 if (rule->windomain == NULL || windomain == NULL ||
1168 1168 strcmp(rule->windomain, windomain) != 0) {
1169 1169 if (rule->windomain != NULL) {
1170 1170 free(rule->windomain);
1171 1171 rule->windomain = NULL;
1172 1172 }
1173 1173 if (windomain != NULL)
1174 1174 rule->windomain = strdup(windomain);
1175 1175 }
1176 1176
1177 1177 if (rule->winname == NULL || winname == NULL ||
1178 1178 strcmp(rule->winname, winname) != 0) {
1179 1179 if (rule->winname != NULL) {
1180 1180 free(rule->winname);
1181 1181 rule->winname = NULL;
1182 1182 }
1183 1183 if (winname != NULL)
1184 1184 rule->winname = strdup(winname);
1185 1185 }
1186 1186
1187 1187 if (rule->unixname == NULL || unixname == NULL ||
1188 1188 strcmp(rule->unixname, unixname) != 0) {
1189 1189 if (rule->unixname != NULL) {
1190 1190 free(rule->unixname);
1191 1191 rule->unixname = NULL;
1192 1192 }
1193 1193 if (unixname != NULL)
1194 1194 rule->unixname = strdup(unixname);
1195 1195 }
1196 1196
1197 1197 rule->is_user = is_user;
1198 1198 rule->is_wuser = is_wuser;
1199 1199 rule->is_nt4 = is_nt4;
1200 1200 rule->direction = direction;
1201 1201 }
1202 1202
1203 1203 /*
1204 1204 * Lookup well-known SIDs table either by winname or by SID.
1205 1205 *
1206 1206 * If the given winname or SID is a well-known SID then we set is_wksid
1207 1207 * variable and then proceed to see if the SID has a hard mapping to
1208 1208 * a particular UID/GID (Ex: Creator Owner/Creator Group mapped to
1209 1209 * fixed ephemeral ids). The direction flag indicates whether we have
1210 1210 * a mapping; UNDEF indicates that we do not.
1211 1211 *
1212 1212 * If we find a mapping then we return success, except for the
1213 1213 * special case of IDMAP_SENTINEL_PID which indicates an inhibited mapping.
1214 1214 *
1215 1215 * If we find a matching entry, but no mapping, we supply SID, name, and type
1216 1216 * information and return "not found". Higher layers will probably
1217 1217 * do ephemeral mapping.
1218 1218 *
1219 1219 * If we do not find a match, we return "not found" and leave the question
1220 1220 * to higher layers.
1221 1221 */
1222 1222 static
1223 1223 idmap_retcode
1224 1224 lookup_wksids_sid2pid(idmap_mapping *req, idmap_id_res *res, int *is_wksid)
1225 1225 {
1226 1226 const wksids_table_t *wksid;
1227 1227
1228 1228 *is_wksid = 0;
1229 1229
1230 1230 assert(req->id1.idmap_id_u.sid.prefix != NULL ||
1231 1231 req->id1name != NULL);
1232 1232
1233 1233 if (req->id1.idmap_id_u.sid.prefix != NULL) {
1234 1234 wksid = find_wksid_by_sid(req->id1.idmap_id_u.sid.prefix,
1235 1235 req->id1.idmap_id_u.sid.rid, res->id.idtype);
1236 1236 } else {
1237 1237 wksid = find_wksid_by_name(req->id1name, req->id1domain,
1238 1238 res->id.idtype);
1239 1239 }
1240 1240 if (wksid == NULL)
1241 1241 return (IDMAP_ERR_NOTFOUND);
1242 1242
1243 1243 /* Found matching entry. */
1244 1244
1245 1245 /* Fill in name if it was not already there. */
1246 1246 if (req->id1name == NULL) {
1247 1247 req->id1name = strdup(wksid->winname);
1248 1248 if (req->id1name == NULL)
1249 1249 return (IDMAP_ERR_MEMORY);
1250 1250 }
1251 1251
1252 1252 /* Fill in SID if it was not already there */
1253 1253 if (req->id1.idmap_id_u.sid.prefix == NULL) {
1254 1254 if (wksid->sidprefix != NULL) {
1255 1255 req->id1.idmap_id_u.sid.prefix =
1256 1256 strdup(wksid->sidprefix);
1257 1257 } else {
1258 1258 RDLOCK_CONFIG();
1259 1259 req->id1.idmap_id_u.sid.prefix =
1260 1260 strdup(_idmapdstate.cfg->pgcfg.machine_sid);
1261 1261 UNLOCK_CONFIG();
1262 1262 }
1263 1263 if (req->id1.idmap_id_u.sid.prefix == NULL)
1264 1264 return (IDMAP_ERR_MEMORY);
1265 1265 req->id1.idmap_id_u.sid.rid = wksid->rid;
1266 1266 }
1267 1267
1268 1268 /* Fill in the canonical domain if not already there */
1269 1269 if (req->id1domain == NULL) {
1270 1270 const char *dom;
1271 1271
1272 1272 RDLOCK_CONFIG();
1273 1273 if (wksid->domain != NULL)
1274 1274 dom = wksid->domain;
1275 1275 else
1276 1276 dom = _idmapdstate.hostname;
1277 1277 req->id1domain = strdup(dom);
1278 1278 UNLOCK_CONFIG();
1279 1279 if (req->id1domain == NULL)
1280 1280 return (IDMAP_ERR_MEMORY);
1281 1281 }
1282 1282
1283 1283 *is_wksid = 1;
1284 1284 req->direction |= _IDMAP_F_DONT_UPDATE_NAMECACHE;
1285 1285
1286 1286 req->id1.idtype = wksid->is_wuser ? IDMAP_USID : IDMAP_GSID;
1287 1287
1288 1288 if (res->id.idtype == IDMAP_POSIXID) {
1289 1289 res->id.idtype = wksid->is_wuser ? IDMAP_UID : IDMAP_GID;
1290 1290 }
1291 1291
1292 1292 if (wksid->direction == IDMAP_DIRECTION_UNDEF) {
1293 1293 /*
1294 1294 * We don't have a mapping
1295 1295 * (But note that we may have supplied SID, name, or type
1296 1296 * information.)
1297 1297 */
1298 1298 return (IDMAP_ERR_NOTFOUND);
1299 1299 }
1300 1300
1301 1301 /*
1302 1302 * We have an explicit mapping.
1303 1303 */
1304 1304 if (wksid->pid == IDMAP_SENTINEL_PID) {
1305 1305 /*
1306 1306 * ... which is that mapping is inhibited.
1307 1307 */
1308 1308 return (IDMAP_ERR_NOMAPPING);
1309 1309 }
1310 1310
1311 1311 switch (res->id.idtype) {
1312 1312 case IDMAP_UID:
1313 1313 res->id.idmap_id_u.uid = wksid->pid;
1314 1314 break;
1315 1315 case IDMAP_GID:
1316 1316 res->id.idmap_id_u.gid = wksid->pid;
1317 1317 break;
1318 1318 default:
1319 1319 /* IDMAP_POSIXID is eliminated above */
1320 1320 return (IDMAP_ERR_NOTSUPPORTED);
1321 1321 }
1322 1322
1323 1323 res->direction = wksid->direction;
1324 1324 res->info.how.map_type = IDMAP_MAP_TYPE_KNOWN_SID;
1325 1325 res->info.src = IDMAP_MAP_SRC_HARD_CODED;
1326 1326 return (IDMAP_SUCCESS);
1327 1327 }
1328 1328
1329 1329
1330 1330 /*
1331 1331 * Look for an entry mapping a PID to a SID.
1332 1332 *
1333 1333 * Note that direction=UNDEF entries do not specify a mapping,
1334 1334 * and that IDMAP_SENTINEL_PID entries represent either an inhibited
1335 1335 * mapping or an ephemeral mapping. We don't handle either here;
1336 1336 * they are filtered out by find_wksid_by_pid.
1337 1337 */
1338 1338 static
1339 1339 idmap_retcode
1340 1340 lookup_wksids_pid2sid(idmap_mapping *req, idmap_id_res *res, int is_user)
1341 1341 {
1342 1342 const wksids_table_t *wksid;
1343 1343
1344 1344 wksid = find_wksid_by_pid(req->id1.idmap_id_u.uid, is_user);
1345 1345 if (wksid == NULL)
1346 1346 return (IDMAP_ERR_NOTFOUND);
1347 1347
1348 1348 if (res->id.idtype == IDMAP_SID) {
1349 1349 res->id.idtype = wksid->is_wuser ? IDMAP_USID : IDMAP_GSID;
1350 1350 }
1351 1351 res->id.idmap_id_u.sid.rid = wksid->rid;
1352 1352
1353 1353 if (wksid->sidprefix != NULL) {
1354 1354 res->id.idmap_id_u.sid.prefix =
1355 1355 strdup(wksid->sidprefix);
1356 1356 } else {
1357 1357 RDLOCK_CONFIG();
1358 1358 res->id.idmap_id_u.sid.prefix =
1359 1359 strdup(_idmapdstate.cfg->pgcfg.machine_sid);
1360 1360 UNLOCK_CONFIG();
1361 1361 }
1362 1362
1363 1363 if (res->id.idmap_id_u.sid.prefix == NULL) {
1364 1364 idmapdlog(LOG_ERR, "Out of memory");
1365 1365 return (IDMAP_ERR_MEMORY);
1366 1366 }
1367 1367
1368 1368 /* Fill in name if it was not already there. */
1369 1369 if (req->id2name == NULL) {
1370 1370 req->id2name = strdup(wksid->winname);
1371 1371 if (req->id2name == NULL)
1372 1372 return (IDMAP_ERR_MEMORY);
1373 1373 }
1374 1374
1375 1375 /* Fill in the canonical domain if not already there */
1376 1376 if (req->id2domain == NULL) {
1377 1377 const char *dom;
1378 1378
1379 1379 RDLOCK_CONFIG();
1380 1380 if (wksid->domain != NULL)
1381 1381 dom = wksid->domain;
1382 1382 else
1383 1383 dom = _idmapdstate.hostname;
1384 1384 req->id2domain = strdup(dom);
1385 1385 UNLOCK_CONFIG();
1386 1386 if (req->id2domain == NULL)
1387 1387 return (IDMAP_ERR_MEMORY);
1388 1388 }
1389 1389
1390 1390 res->direction = wksid->direction;
1391 1391 res->info.how.map_type = IDMAP_MAP_TYPE_KNOWN_SID;
1392 1392 res->info.src = IDMAP_MAP_SRC_HARD_CODED;
1393 1393 return (IDMAP_SUCCESS);
1394 1394 }
1395 1395
1396 1396 /*
1397 1397 * Look up a name in the wksids list, matching name and, if supplied, domain,
1398 1398 * and extract data.
1399 1399 *
1400 1400 * Given:
1401 1401 * name Windows user name
1402 1402 * domain Windows domain name (or NULL)
1403 1403 *
1404 1404 * Return: Error code
1405 1405 *
1406 1406 * *canonname canonical name (if canonname non-NULL) [1]
1407 1407 * *canondomain canonical domain (if canondomain non-NULL) [1]
1408 1408 * *sidprefix SID prefix (if sidprefix non-NULL) [1]
1409 1409 * *rid RID (if rid non-NULL) [2]
1410 1410 * *type Type (if type non-NULL) [2]
1411 1411 *
1412 1412 * [1] malloc'ed, NULL on error
1413 1413 * [2] Undefined on error
1414 1414 */
1415 1415 idmap_retcode
1416 1416 lookup_wksids_name2sid(
1417 1417 const char *name,
1418 1418 const char *domain,
1419 1419 char **canonname,
1420 1420 char **canondomain,
1421 1421 char **sidprefix,
1422 1422 idmap_rid_t *rid,
1423 1423 idmap_id_type *type)
1424 1424 {
1425 1425 const wksids_table_t *wksid;
1426 1426
1427 1427 if (sidprefix != NULL)
1428 1428 *sidprefix = NULL;
1429 1429 if (canonname != NULL)
1430 1430 *canonname = NULL;
1431 1431 if (canondomain != NULL)
1432 1432 *canondomain = NULL;
1433 1433
1434 1434 wksid = find_wksid_by_name(name, domain, IDMAP_POSIXID);
1435 1435 if (wksid == NULL)
1436 1436 return (IDMAP_ERR_NOTFOUND);
1437 1437
1438 1438 if (sidprefix != NULL) {
1439 1439 if (wksid->sidprefix != NULL) {
1440 1440 *sidprefix = strdup(wksid->sidprefix);
1441 1441 } else {
1442 1442 RDLOCK_CONFIG();
1443 1443 *sidprefix = strdup(
1444 1444 _idmapdstate.cfg->pgcfg.machine_sid);
1445 1445 UNLOCK_CONFIG();
1446 1446 }
1447 1447 if (*sidprefix == NULL)
1448 1448 goto nomem;
1449 1449 }
1450 1450
1451 1451 if (rid != NULL)
1452 1452 *rid = wksid->rid;
1453 1453
1454 1454 if (canonname != NULL) {
1455 1455 *canonname = strdup(wksid->winname);
1456 1456 if (*canonname == NULL)
1457 1457 goto nomem;
1458 1458 }
1459 1459
1460 1460 if (canondomain != NULL) {
1461 1461 if (wksid->domain != NULL) {
1462 1462 *canondomain = strdup(wksid->domain);
1463 1463 } else {
1464 1464 RDLOCK_CONFIG();
1465 1465 *canondomain = strdup(_idmapdstate.hostname);
1466 1466 UNLOCK_CONFIG();
1467 1467 }
1468 1468 if (*canondomain == NULL)
1469 1469 goto nomem;
1470 1470 }
1471 1471
1472 1472 if (type != NULL)
1473 1473 *type = (wksid->is_wuser) ?
1474 1474 IDMAP_USID : IDMAP_GSID;
1475 1475
1476 1476 return (IDMAP_SUCCESS);
1477 1477
1478 1478 nomem:
1479 1479 idmapdlog(LOG_ERR, "Out of memory");
1480 1480
1481 1481 if (sidprefix != NULL) {
1482 1482 free(*sidprefix);
1483 1483 *sidprefix = NULL;
1484 1484 }
1485 1485
1486 1486 if (canonname != NULL) {
1487 1487 free(*canonname);
1488 1488 *canonname = NULL;
1489 1489 }
1490 1490
1491 1491 if (canondomain != NULL) {
1492 1492 free(*canondomain);
1493 1493 *canondomain = NULL;
1494 1494 }
1495 1495
1496 1496 return (IDMAP_ERR_MEMORY);
1497 1497 }
1498 1498
1499 1499 static
1500 1500 idmap_retcode
1501 1501 lookup_cache_sid2pid(sqlite *cache, idmap_mapping *req, idmap_id_res *res)
1502 1502 {
1503 1503 char *end;
1504 1504 char *sql = NULL;
1505 1505 const char **values;
1506 1506 sqlite_vm *vm = NULL;
1507 1507 int ncol, is_user;
1508 1508 uid_t pid;
1509 1509 time_t curtime, exp;
1510 1510 idmap_retcode retcode;
1511 1511 char *is_user_string, *lower_name;
1512 1512
1513 1513 /* Current time */
1514 1514 errno = 0;
1515 1515 if ((curtime = time(NULL)) == (time_t)-1) {
1516 1516 idmapdlog(LOG_ERR, "Failed to get current time (%s)",
1517 1517 strerror(errno));
1518 1518 retcode = IDMAP_ERR_INTERNAL;
1519 1519 goto out;
1520 1520 }
1521 1521
1522 1522 switch (res->id.idtype) {
1523 1523 case IDMAP_UID:
1524 1524 is_user_string = "1";
1525 1525 break;
1526 1526 case IDMAP_GID:
1527 1527 is_user_string = "0";
1528 1528 break;
1529 1529 case IDMAP_POSIXID:
1530 1530 /* the non-diagonal mapping */
1531 1531 is_user_string = "is_wuser";
1532 1532 break;
1533 1533 default:
1534 1534 retcode = IDMAP_ERR_NOTSUPPORTED;
1535 1535 goto out;
1536 1536 }
1537 1537
1538 1538 /* SQL to lookup the cache */
1539 1539
1540 1540 if (req->id1.idmap_id_u.sid.prefix != NULL) {
1541 1541 sql = sqlite_mprintf("SELECT pid, is_user, expiration, "
1542 1542 "unixname, u2w, is_wuser, "
1543 1543 "map_type, map_dn, map_attr, map_value, "
1544 1544 "map_windomain, map_winname, map_unixname, map_is_nt4 "
1545 1545 "FROM idmap_cache WHERE is_user = %s AND "
1546 1546 "sidprefix = %Q AND rid = %u AND w2u = 1 AND "
1547 1547 "(pid >= 2147483648 OR "
1548 1548 "(expiration = 0 OR expiration ISNULL OR "
1549 1549 "expiration > %d));",
1550 1550 is_user_string, req->id1.idmap_id_u.sid.prefix,
1551 1551 req->id1.idmap_id_u.sid.rid, curtime);
1552 1552 } else if (req->id1name != NULL) {
1553 1553 if ((lower_name = tolower_u8(req->id1name)) == NULL)
1554 1554 lower_name = req->id1name;
1555 1555 sql = sqlite_mprintf("SELECT pid, is_user, expiration, "
1556 1556 "unixname, u2w, is_wuser, "
1557 1557 "map_type, map_dn, map_attr, map_value, "
1558 1558 "map_windomain, map_winname, map_unixname, map_is_nt4 "
1559 1559 "FROM idmap_cache WHERE is_user = %s AND "
1560 1560 "winname = %Q AND windomain = %Q AND w2u = 1 AND "
1561 1561 "(pid >= 2147483648 OR "
1562 1562 "(expiration = 0 OR expiration ISNULL OR "
1563 1563 "expiration > %d));",
1564 1564 is_user_string, lower_name, req->id1domain,
1565 1565 curtime);
1566 1566 if (lower_name != req->id1name)
1567 1567 free(lower_name);
1568 1568 } else {
1569 1569 retcode = IDMAP_ERR_ARG;
1570 1570 goto out;
1571 1571 }
1572 1572 if (sql == NULL) {
1573 1573 idmapdlog(LOG_ERR, "Out of memory");
1574 1574 retcode = IDMAP_ERR_MEMORY;
1575 1575 goto out;
1576 1576 }
1577 1577 retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol,
1578 1578 14, &values);
1579 1579 sqlite_freemem(sql);
1580 1580
1581 1581 if (retcode == IDMAP_ERR_NOTFOUND) {
1582 1582 goto out;
1583 1583 } else if (retcode == IDMAP_SUCCESS) {
1584 1584 /* sanity checks */
1585 1585 if (values[0] == NULL || values[1] == NULL) {
1586 1586 retcode = IDMAP_ERR_CACHE;
1587 1587 goto out;
1588 1588 }
1589 1589
1590 1590 pid = strtoul(values[0], &end, 10);
1591 1591 is_user = strncmp(values[1], "0", 2) ? 1 : 0;
1592 1592
1593 1593 if (is_user) {
1594 1594 res->id.idtype = IDMAP_UID;
1595 1595 res->id.idmap_id_u.uid = pid;
1596 1596 } else {
1597 1597 res->id.idtype = IDMAP_GID;
1598 1598 res->id.idmap_id_u.gid = pid;
1599 1599 }
1600 1600
1601 1601 /*
1602 1602 * We may have an expired ephemeral mapping. Consider
1603 1603 * the expired entry as valid if we are not going to
1604 1604 * perform name-based mapping. But do not renew the
1605 1605 * expiration.
1606 1606 * If we will be doing name-based mapping then store the
1607 1607 * ephemeral pid in the result so that we can use it
1608 1608 * if we end up doing dynamic mapping again.
1609 1609 */
1610 1610 if (!DO_NOT_ALLOC_NEW_ID_MAPPING(req) &&
1611 1611 !AVOID_NAMESERVICE(req) &&
1612 1612 IDMAP_ID_IS_EPHEMERAL(pid) && values[2] != NULL) {
1613 1613 exp = strtoll(values[2], &end, 10);
1614 1614 if (exp && exp <= curtime) {
1615 1615 /* Store the ephemeral pid */
1616 1616 res->direction = IDMAP_DIRECTION_BI;
1617 1617 req->direction |= is_user
1618 1618 ? _IDMAP_F_EXP_EPH_UID
1619 1619 : _IDMAP_F_EXP_EPH_GID;
1620 1620 retcode = IDMAP_ERR_NOTFOUND;
1621 1621 }
1622 1622 }
1623 1623 }
1624 1624
1625 1625 out:
1626 1626 if (retcode == IDMAP_SUCCESS) {
1627 1627 if (values[4] != NULL)
1628 1628 res->direction =
1629 1629 (strtol(values[4], &end, 10) == 0)?
1630 1630 IDMAP_DIRECTION_W2U:IDMAP_DIRECTION_BI;
1631 1631 else
1632 1632 res->direction = IDMAP_DIRECTION_W2U;
1633 1633
1634 1634 if (values[3] != NULL) {
1635 1635 if (req->id2name != NULL)
1636 1636 free(req->id2name);
1637 1637 req->id2name = strdup(values[3]);
1638 1638 if (req->id2name == NULL) {
1639 1639 idmapdlog(LOG_ERR, "Out of memory");
1640 1640 retcode = IDMAP_ERR_MEMORY;
1641 1641 }
1642 1642 }
1643 1643
1644 1644 req->id1.idtype = strncmp(values[5], "0", 2) ?
1645 1645 IDMAP_USID : IDMAP_GSID;
1646 1646
1647 1647 if (req->flag & IDMAP_REQ_FLG_MAPPING_INFO) {
1648 1648 res->info.src = IDMAP_MAP_SRC_CACHE;
1649 1649 res->info.how.map_type = strtoul(values[6], &end, 10);
1650 1650 switch (res->info.how.map_type) {
1651 1651 case IDMAP_MAP_TYPE_DS_AD:
1652 1652 res->info.how.idmap_how_u.ad.dn =
1653 1653 strdup(values[7]);
1654 1654 res->info.how.idmap_how_u.ad.attr =
1655 1655 strdup(values[8]);
1656 1656 res->info.how.idmap_how_u.ad.value =
1657 1657 strdup(values[9]);
1658 1658 break;
1659 1659
1660 1660 case IDMAP_MAP_TYPE_DS_NLDAP:
1661 1661 res->info.how.idmap_how_u.nldap.dn =
1662 1662 strdup(values[7]);
1663 1663 res->info.how.idmap_how_u.nldap.attr =
1664 1664 strdup(values[8]);
1665 1665 res->info.how.idmap_how_u.nldap.value =
1666 1666 strdup(values[9]);
1667 1667 break;
1668 1668
1669 1669 case IDMAP_MAP_TYPE_RULE_BASED:
1670 1670 res->info.how.idmap_how_u.rule.windomain =
1671 1671 strdup(values[10]);
1672 1672 res->info.how.idmap_how_u.rule.winname =
1673 1673 strdup(values[11]);
1674 1674 res->info.how.idmap_how_u.rule.unixname =
1675 1675 strdup(values[12]);
1676 1676 res->info.how.idmap_how_u.rule.is_nt4 =
1677 1677 strtoul(values[13], &end, 1);
1678 1678 res->info.how.idmap_how_u.rule.is_user =
1679 1679 is_user;
1680 1680 res->info.how.idmap_how_u.rule.is_wuser =
1681 1681 strtoul(values[5], &end, 1);
1682 1682 break;
1683 1683
1684 1684 case IDMAP_MAP_TYPE_EPHEMERAL:
1685 1685 break;
1686 1686
1687 1687 case IDMAP_MAP_TYPE_LOCAL_SID:
1688 1688 break;
1689 1689
1690 1690 case IDMAP_MAP_TYPE_KNOWN_SID:
1691 1691 break;
1692 1692
1693 1693 case IDMAP_MAP_TYPE_IDMU:
1694 1694 res->info.how.idmap_how_u.idmu.dn =
1695 1695 strdup(values[7]);
1696 1696 res->info.how.idmap_how_u.idmu.attr =
1697 1697 strdup(values[8]);
1698 1698 res->info.how.idmap_how_u.idmu.value =
1699 1699 strdup(values[9]);
1700 1700 break;
1701 1701
1702 1702 default:
1703 1703 /* Unknown mapping type */
1704 1704 assert(FALSE);
1705 1705 }
1706 1706 }
1707 1707 }
1708 1708 if (vm != NULL)
1709 1709 (void) sqlite_finalize(vm, NULL);
1710 1710 return (retcode);
1711 1711 }
1712 1712
1713 1713 /*
1714 1714 * Previous versions used two enumerations for representing types.
1715 1715 * One of those has largely been eliminated, but was used in the
1716 1716 * name cache table and so during an upgrade might still be visible.
1717 1717 * In addition, the test suite prepopulates the cache with these values.
1718 1718 *
1719 1719 * This function translates those old values into the new values.
1720 1720 *
1721 1721 * This code deliberately does not use symbolic values for the legacy
1722 1722 * values. This is the *only* place where they should be used.
1723 1723 */
1724 1724 static
1725 1725 idmap_id_type
1726 1726 xlate_legacy_type(int type)
1727 1727 {
1728 1728 switch (type) {
1729 1729 case -1004: /* _IDMAP_T_USER */
1730 1730 return (IDMAP_USID);
1731 1731 case -1005: /* _IDMAP_T_GROUP */
1732 1732 return (IDMAP_GSID);
1733 1733 default:
1734 1734 return (type);
1735 1735 }
1736 1736 NOTE(NOTREACHED)
1737 1737 }
1738 1738
1739 1739 static
1740 1740 idmap_retcode
1741 1741 lookup_cache_sid2name(sqlite *cache, const char *sidprefix, idmap_rid_t rid,
1742 1742 char **canonname, char **canondomain, idmap_id_type *type)
1743 1743 {
1744 1744 char *end;
1745 1745 char *sql = NULL;
1746 1746 const char **values;
1747 1747 sqlite_vm *vm = NULL;
1748 1748 int ncol;
1749 1749 time_t curtime;
1750 1750 idmap_retcode retcode = IDMAP_SUCCESS;
1751 1751
1752 1752 /* Get current time */
1753 1753 errno = 0;
1754 1754 if ((curtime = time(NULL)) == (time_t)-1) {
1755 1755 idmapdlog(LOG_ERR, "Failed to get current time (%s)",
1756 1756 strerror(errno));
1757 1757 retcode = IDMAP_ERR_INTERNAL;
1758 1758 goto out;
1759 1759 }
1760 1760
1761 1761 /* SQL to lookup the cache */
1762 1762 sql = sqlite_mprintf("SELECT canon_name, domain, type "
1763 1763 "FROM name_cache WHERE "
1764 1764 "sidprefix = %Q AND rid = %u AND "
1765 1765 "(expiration = 0 OR expiration ISNULL OR "
1766 1766 "expiration > %d);",
1767 1767 sidprefix, rid, curtime);
1768 1768 if (sql == NULL) {
1769 1769 idmapdlog(LOG_ERR, "Out of memory");
1770 1770 retcode = IDMAP_ERR_MEMORY;
1771 1771 goto out;
1772 1772 }
1773 1773 retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 3, &values);
1774 1774 sqlite_freemem(sql);
1775 1775
1776 1776 if (retcode == IDMAP_SUCCESS) {
1777 1777 if (type != NULL) {
1778 1778 if (values[2] == NULL) {
1779 1779 retcode = IDMAP_ERR_CACHE;
1780 1780 goto out;
1781 1781 }
1782 1782 *type = xlate_legacy_type(strtol(values[2], &end, 10));
1783 1783 }
1784 1784
1785 1785 if (canonname != NULL && values[0] != NULL) {
1786 1786 if ((*canonname = strdup(values[0])) == NULL) {
1787 1787 idmapdlog(LOG_ERR, "Out of memory");
1788 1788 retcode = IDMAP_ERR_MEMORY;
1789 1789 goto out;
1790 1790 }
1791 1791 }
1792 1792
1793 1793 if (canondomain != NULL && values[1] != NULL) {
1794 1794 if ((*canondomain = strdup(values[1])) == NULL) {
1795 1795 if (canonname != NULL) {
1796 1796 free(*canonname);
1797 1797 *canonname = NULL;
1798 1798 }
1799 1799 idmapdlog(LOG_ERR, "Out of memory");
1800 1800 retcode = IDMAP_ERR_MEMORY;
1801 1801 goto out;
1802 1802 }
1803 1803 }
1804 1804 }
1805 1805
1806 1806 out:
1807 1807 if (vm != NULL)
1808 1808 (void) sqlite_finalize(vm, NULL);
1809 1809 return (retcode);
1810 1810 }
1811 1811
1812 1812 /*
1813 1813 * Given SID, find winname using name_cache OR
1814 1814 * Given winname, find SID using name_cache.
1815 1815 * Used when mapping win to unix i.e. req->id1 is windows id and
1816 1816 * req->id2 is unix id
1817 1817 */
1818 1818 static
1819 1819 idmap_retcode
1820 1820 lookup_name_cache(sqlite *cache, idmap_mapping *req, idmap_id_res *res)
1821 1821 {
1822 1822 idmap_id_type type = -1;
1823 1823 idmap_retcode retcode;
1824 1824 char *sidprefix = NULL;
1825 1825 idmap_rid_t rid;
1826 1826 char *name = NULL, *domain = NULL;
1827 1827
1828 1828 /* Done if we've both sid and winname */
1829 1829 if (req->id1.idmap_id_u.sid.prefix != NULL && req->id1name != NULL) {
1830 1830 /* Don't bother TRACE()ing, too boring */
1831 1831 return (IDMAP_SUCCESS);
1832 1832 }
1833 1833
1834 1834 if (req->id1.idmap_id_u.sid.prefix != NULL) {
1835 1835 /* Lookup sid to winname */
1836 1836 retcode = lookup_cache_sid2name(cache,
1837 1837 req->id1.idmap_id_u.sid.prefix,
1838 1838 req->id1.idmap_id_u.sid.rid, &name, &domain, &type);
1839 1839 } else {
1840 1840 /* Lookup winame to sid */
1841 1841 retcode = lookup_cache_name2sid(cache, req->id1name,
1842 1842 req->id1domain, &name, &sidprefix, &rid, &type);
1843 1843 }
1844 1844
1845 1845 if (retcode != IDMAP_SUCCESS) {
1846 1846 if (retcode == IDMAP_ERR_NOTFOUND) {
1847 1847 TRACE(req, res, "Not found in name cache");
1848 1848 } else {
1849 1849 TRACE(req, res, "Name cache lookup error=%d", retcode);
1850 1850 }
1851 1851 free(name);
1852 1852 free(domain);
1853 1853 free(sidprefix);
1854 1854 return (retcode);
1855 1855 }
1856 1856
1857 1857 req->id1.idtype = type;
1858 1858
1859 1859 req->direction |= _IDMAP_F_DONT_UPDATE_NAMECACHE;
1860 1860
1861 1861 /*
1862 1862 * If we found canonical names or domain, use them instead of
1863 1863 * the existing values.
1864 1864 */
1865 1865 if (name != NULL) {
1866 1866 free(req->id1name);
1867 1867 req->id1name = name;
1868 1868 }
1869 1869 if (domain != NULL) {
1870 1870 free(req->id1domain);
1871 1871 req->id1domain = domain;
1872 1872 }
1873 1873
1874 1874 if (req->id1.idmap_id_u.sid.prefix == NULL) {
1875 1875 req->id1.idmap_id_u.sid.prefix = sidprefix;
1876 1876 req->id1.idmap_id_u.sid.rid = rid;
1877 1877 }
1878 1878
1879 1879 TRACE(req, res, "Found in name cache");
1880 1880 return (retcode);
1881 1881 }
1882 1882
1883 1883
1884 1884
1885 1885 static int
1886 1886 ad_lookup_batch_int(lookup_state_t *state, idmap_mapping_batch *batch,
1887 1887 idmap_ids_res *result, adutils_ad_t *dir, int how_local,
1888 1888 int *num_processed)
1889 1889 {
1890 1890 idmap_retcode retcode;
1891 1891 int i, num_queued, is_wuser, is_user;
1892 1892 int next_request;
1893 1893 int retries = 0, esidtype;
1894 1894 char **unixname;
1895 1895 idmap_mapping *req;
1896 1896 idmap_id_res *res;
1897 1897 idmap_query_state_t *qs = NULL;
1898 1898 idmap_how *how;
1899 1899 char **dn, **attr, **value;
1900 1900
1901 1901 *num_processed = 0;
1902 1902
1903 1903 /*
1904 1904 * Since req->id2.idtype is unused, we will use it here
1905 1905 * to retrieve the value of sid_type. But it needs to be
1906 1906 * reset to IDMAP_NONE before we return to prevent xdr
1907 1907 * from mis-interpreting req->id2 when it tries to free
1908 1908 * the input argument. Other option is to allocate an
1909 1909 * array of integers and use it instead for the batched
1910 1910 * call. But why un-necessarily allocate memory. That may
1911 1911 * be an option if req->id2.idtype cannot be re-used in
1912 1912 * future.
1913 1913 *
1914 1914 * Similarly, we use req->id2.idmap_id_u.uid to return
1915 1915 * uidNumber or gidNumber supplied by IDMU, and reset it
1916 1916 * back to IDMAP_SENTINEL_PID when we're done. Note that
1917 1917 * the query always puts the result in req->id2.idmap_id_u.uid,
1918 1918 * not .gid.
1919 1919 */
1920 1920 retry:
1921 1921 retcode = idmap_lookup_batch_start(dir, state->ad_nqueries,
1922 1922 state->directory_based_mapping,
1923 1923 state->defdom,
1924 1924 &qs);
1925 1925 if (retcode != IDMAP_SUCCESS) {
1926 1926 if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR &&
1927 1927 retries++ < ADUTILS_DEF_NUM_RETRIES)
1928 1928 goto retry;
1929 1929 degrade_svc(1, "failed to create batch for AD lookup");
1930 1930 goto out;
1931 1931 }
1932 1932 num_queued = 0;
1933 1933
1934 1934 restore_svc();
1935 1935
1936 1936 if (how_local & FOREST_IS_LOCAL) {
1937 1937 /*
1938 1938 * Directory based name mapping is only performed within the
1939 1939 * joined forest. We don't trust other "trusted"
1940 1940 * forests to provide DS-based name mapping information because
1941 1941 * AD's definition of "cross-forest trust" does not encompass
1942 1942 * this sort of behavior.
1943 1943 */
1944 1944 idmap_lookup_batch_set_unixattr(qs,
1945 1945 state->ad_unixuser_attr, state->ad_unixgroup_attr);
1946 1946 }
1947 1947
1948 1948 for (i = 0; i < batch->idmap_mapping_batch_len; i++) {
1949 1949 req = &batch->idmap_mapping_batch_val[i];
1950 1950 res = &result->ids.ids_val[i];
1951 1951 how = &res->info.how;
1952 1952
1953 1953 retcode = IDMAP_SUCCESS;
1954 1954 req->id2.idtype = IDMAP_NONE;
1955 1955 req->id2.idmap_id_u.uid = IDMAP_SENTINEL_PID;
1956 1956
1957 1957 /* Skip if no AD lookup required */
1958 1958 if (!(req->direction & _IDMAP_F_LOOKUP_AD))
1959 1959 continue;
1960 1960
1961 1961 /* Skip if we've already tried and gotten a "not found" */
1962 1962 if (req->direction & _IDMAP_F_LOOKUP_OTHER_AD)
1963 1963 continue;
1964 1964
1965 1965 /* Skip if we've already either succeeded or failed */
1966 1966 if (res->retcode != IDMAP_ERR_RETRIABLE_NET_ERR)
1967 1967 continue;
1968 1968
1969 1969 if (IS_ID_SID(req->id1)) {
1970 1970
1971 1971 /* win2unix request: */
1972 1972
1973 1973 posix_id_t *pid = NULL;
1974 1974 unixname = dn = attr = value = NULL;
1975 1975 esidtype = IDMAP_SID;
1976 1976 if (state->directory_based_mapping ==
1977 1977 DIRECTORY_MAPPING_NAME &&
1978 1978 req->id2name == NULL) {
1979 1979 if (res->id.idtype == IDMAP_UID &&
1980 1980 AD_OR_MIXED(state->nm_siduid)) {
1981 1981 esidtype = IDMAP_USID;
1982 1982 unixname = &req->id2name;
1983 1983 } else if (res->id.idtype == IDMAP_GID &&
1984 1984 AD_OR_MIXED(state->nm_sidgid)) {
1985 1985 esidtype = IDMAP_GSID;
1986 1986 unixname = &req->id2name;
1987 1987 } else if (AD_OR_MIXED(state->nm_siduid) ||
1988 1988 AD_OR_MIXED(state->nm_sidgid)) {
1989 1989 unixname = &req->id2name;
1990 1990 }
1991 1991
1992 1992 if (unixname != NULL) {
1993 1993 /*
1994 1994 * Get how info for DS-based name
1995 1995 * mapping only if AD or MIXED
1996 1996 * mode is enabled.
1997 1997 */
1998 1998 idmap_how_clear(&res->info.how);
1999 1999 res->info.src = IDMAP_MAP_SRC_NEW;
2000 2000 how->map_type = IDMAP_MAP_TYPE_DS_AD;
2001 2001 dn = &how->idmap_how_u.ad.dn;
2002 2002 attr = &how->idmap_how_u.ad.attr;
2003 2003 value = &how->idmap_how_u.ad.value;
2004 2004 }
2005 2005 } else if (state->directory_based_mapping ==
2006 2006 DIRECTORY_MAPPING_IDMU &&
2007 2007 (how_local & DOMAIN_IS_LOCAL)) {
2008 2008 /*
2009 2009 * Ensure that we only do IDMU processing
2010 2010 * when querying the domain we've joined.
2011 2011 */
2012 2012 pid = &req->id2.idmap_id_u.uid;
2013 2013 /*
2014 2014 * Get how info for IDMU based mapping.
2015 2015 */
2016 2016 idmap_how_clear(&res->info.how);
2017 2017 res->info.src = IDMAP_MAP_SRC_NEW;
2018 2018 how->map_type = IDMAP_MAP_TYPE_IDMU;
2019 2019 dn = &how->idmap_how_u.idmu.dn;
2020 2020 attr = &how->idmap_how_u.idmu.attr;
2021 2021 value = &how->idmap_how_u.idmu.value;
2022 2022 }
2023 2023
2024 2024 if (req->id1.idmap_id_u.sid.prefix != NULL) {
2025 2025 /* Lookup AD by SID */
2026 2026 retcode = idmap_sid2name_batch_add1(
2027 2027 qs, req->id1.idmap_id_u.sid.prefix,
2028 2028 &req->id1.idmap_id_u.sid.rid, esidtype,
2029 2029 dn, attr, value,
2030 2030 (req->id1name == NULL) ?
2031 2031 &req->id1name : NULL,
2032 2032 (req->id1domain == NULL) ?
2033 2033 &req->id1domain : NULL,
2034 2034 &req->id2.idtype, unixname,
2035 2035 pid,
2036 2036 &res->retcode);
2037 2037 if (retcode == IDMAP_SUCCESS)
2038 2038 num_queued++;
2039 2039 } else {
2040 2040 /* Lookup AD by winname */
2041 2041 assert(req->id1name != NULL);
2042 2042 retcode = idmap_name2sid_batch_add1(
2043 2043 qs, req->id1name, req->id1domain,
2044 2044 esidtype,
2045 2045 dn, attr, value,
2046 2046 &req->id1name,
2047 2047 &req->id1.idmap_id_u.sid.prefix,
2048 2048 &req->id1.idmap_id_u.sid.rid,
2049 2049 &req->id2.idtype, unixname,
2050 2050 pid,
2051 2051 &res->retcode);
2052 2052 if (retcode == IDMAP_SUCCESS)
2053 2053 num_queued++;
2054 2054 }
2055 2055
2056 2056 } else if (IS_ID_UID(req->id1) || IS_ID_GID(req->id1)) {
2057 2057
2058 2058 /* unix2win request: */
2059 2059
2060 2060 if (res->id.idmap_id_u.sid.prefix != NULL &&
2061 2061 req->id2name != NULL) {
2062 2062 /* Already have SID and winname. done */
2063 2063 res->retcode = IDMAP_SUCCESS;
2064 2064 continue;
2065 2065 }
2066 2066
2067 2067 if (res->id.idmap_id_u.sid.prefix != NULL) {
2068 2068 /*
2069 2069 * SID but no winname -- lookup AD by
2070 2070 * SID to get winname.
2071 2071 * how info is not needed here because
2072 2072 * we are not retrieving unixname from
2073 2073 * AD.
2074 2074 */
2075 2075
2076 2076 retcode = idmap_sid2name_batch_add1(
2077 2077 qs, res->id.idmap_id_u.sid.prefix,
2078 2078 &res->id.idmap_id_u.sid.rid,
2079 2079 IDMAP_POSIXID,
2080 2080 NULL, NULL, NULL,
2081 2081 &req->id2name,
2082 2082 &req->id2domain, &req->id2.idtype,
2083 2083 NULL, NULL, &res->retcode);
2084 2084 if (retcode == IDMAP_SUCCESS)
2085 2085 num_queued++;
2086 2086 } else if (req->id2name != NULL) {
2087 2087 /*
2088 2088 * winname but no SID -- lookup AD by
2089 2089 * winname to get SID.
2090 2090 * how info is not needed here because
2091 2091 * we are not retrieving unixname from
2092 2092 * AD.
2093 2093 */
2094 2094 retcode = idmap_name2sid_batch_add1(
2095 2095 qs, req->id2name, req->id2domain,
2096 2096 IDMAP_POSIXID,
2097 2097 NULL, NULL, NULL, NULL,
2098 2098 &res->id.idmap_id_u.sid.prefix,
2099 2099 &res->id.idmap_id_u.sid.rid,
2100 2100 &req->id2.idtype, NULL,
2101 2101 NULL,
2102 2102 &res->retcode);
2103 2103 if (retcode == IDMAP_SUCCESS)
2104 2104 num_queued++;
2105 2105 } else if (state->directory_based_mapping ==
2106 2106 DIRECTORY_MAPPING_IDMU &&
2107 2107 (how_local & DOMAIN_IS_LOCAL)) {
2108 2108 assert(req->id1.idmap_id_u.uid !=
2109 2109 IDMAP_SENTINEL_PID);
2110 2110 is_user = IS_ID_UID(req->id1);
2111 2111 if (res->id.idtype == IDMAP_USID)
2112 2112 is_wuser = 1;
2113 2113 else if (res->id.idtype == IDMAP_GSID)
2114 2114 is_wuser = 0;
2115 2115 else
2116 2116 is_wuser = is_user;
2117 2117
2118 2118 /* IDMU can't do diagonal mappings */
2119 2119 if (is_user != is_wuser)
2120 2120 continue;
2121 2121
2122 2122 idmap_how_clear(&res->info.how);
2123 2123 res->info.src = IDMAP_MAP_SRC_NEW;
2124 2124 how->map_type = IDMAP_MAP_TYPE_IDMU;
2125 2125 retcode = idmap_pid2sid_batch_add1(
2126 2126 qs, req->id1.idmap_id_u.uid, is_user,
2127 2127 &how->idmap_how_u.ad.dn,
2128 2128 &how->idmap_how_u.ad.attr,
2129 2129 &how->idmap_how_u.ad.value,
2130 2130 &res->id.idmap_id_u.sid.prefix,
2131 2131 &res->id.idmap_id_u.sid.rid,
2132 2132 &req->id2name, &req->id2domain,
2133 2133 &req->id2.idtype, &res->retcode);
2134 2134 if (retcode == IDMAP_SUCCESS)
2135 2135 num_queued++;
2136 2136 } else if (req->id1name != NULL) {
2137 2137 /*
2138 2138 * No SID and no winname but we've unixname.
2139 2139 * Lookup AD by unixname to get SID.
2140 2140 */
2141 2141 is_user = (IS_ID_UID(req->id1)) ? 1 : 0;
2142 2142 if (res->id.idtype == IDMAP_USID)
2143 2143 is_wuser = 1;
2144 2144 else if (res->id.idtype == IDMAP_GSID)
2145 2145 is_wuser = 0;
2146 2146 else
2147 2147 is_wuser = is_user;
2148 2148
2149 2149 idmap_how_clear(&res->info.how);
2150 2150 res->info.src = IDMAP_MAP_SRC_NEW;
2151 2151 how->map_type = IDMAP_MAP_TYPE_DS_AD;
2152 2152 retcode = idmap_unixname2sid_batch_add1(
2153 2153 qs, req->id1name, is_user, is_wuser,
2154 2154 &how->idmap_how_u.ad.dn,
2155 2155 &how->idmap_how_u.ad.attr,
2156 2156 &how->idmap_how_u.ad.value,
2157 2157 &res->id.idmap_id_u.sid.prefix,
2158 2158 &res->id.idmap_id_u.sid.rid,
2159 2159 &req->id2name, &req->id2domain,
2160 2160 &req->id2.idtype, &res->retcode);
2161 2161 if (retcode == IDMAP_SUCCESS)
2162 2162 num_queued++;
2163 2163 }
2164 2164 }
2165 2165
2166 2166 if (retcode == IDMAP_ERR_DOMAIN_NOTFOUND) {
2167 2167 req->direction |= _IDMAP_F_LOOKUP_OTHER_AD;
2168 2168 retcode = IDMAP_SUCCESS;
2169 2169 } else if (retcode != IDMAP_SUCCESS) {
2170 2170 break;
2171 2171 }
2172 2172 } /* End of for loop */
2173 2173
2174 2174 if (retcode == IDMAP_SUCCESS) {
2175 2175 /* add keeps track if we added an entry to the batch */
2176 2176 if (num_queued > 0)
2177 2177 retcode = idmap_lookup_batch_end(&qs);
2178 2178 else
2179 2179 idmap_lookup_release_batch(&qs);
2180 2180 } else {
2181 2181 idmap_lookup_release_batch(&qs);
2182 2182 num_queued = 0;
2183 2183 next_request = i + 1;
2184 2184 }
2185 2185
2186 2186 if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR &&
2187 2187 retries++ < ADUTILS_DEF_NUM_RETRIES)
2188 2188 goto retry;
2189 2189 else if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR)
2190 2190 degrade_svc(1, "some AD lookups timed out repeatedly");
2191 2191
2192 2192 if (retcode != IDMAP_SUCCESS) {
2193 2193 /* Mark any unproccessed requests for an other AD */
2194 2194 for (i = next_request; i < batch->idmap_mapping_batch_len;
2195 2195 i++) {
2196 2196 req = &batch->idmap_mapping_batch_val[i];
2197 2197 req->direction |= _IDMAP_F_LOOKUP_OTHER_AD;
2198 2198
2199 2199 }
2200 2200 }
2201 2201
2202 2202 if (retcode != IDMAP_SUCCESS)
2203 2203 idmapdlog(LOG_NOTICE, "Failed to batch AD lookup requests");
2204 2204
2205 2205 out:
2206 2206 /*
2207 2207 * This loop does the following:
2208 2208 * 1. Reset _IDMAP_F_LOOKUP_AD flag from the request.
2209 2209 * 2. Reset req->id2.idtype to IDMAP_NONE
2210 2210 * 3. If batch_start or batch_add failed then set the status
2211 2211 * of each request marked for AD lookup to that error.
2212 2212 * 4. Evaluate the type of the AD object (i.e. user or group)
2213 2213 * and update the idtype in request.
2214 2214 */
2215 2215 for (i = 0; i < batch->idmap_mapping_batch_len; i++) {
2216 2216 idmap_id_type type;
2217 2217 uid_t posix_id;
2218 2218
2219 2219 req = &batch->idmap_mapping_batch_val[i];
2220 2220 type = req->id2.idtype;
2221 2221 req->id2.idtype = IDMAP_NONE;
2222 2222 posix_id = req->id2.idmap_id_u.uid;
2223 2223 req->id2.idmap_id_u.uid = IDMAP_SENTINEL_PID;
2224 2224 res = &result->ids.ids_val[i];
2225 2225
2226 2226 /*
2227 2227 * If it didn't need AD lookup, ignore it.
2228 2228 */
2229 2229 if (!(req->direction & _IDMAP_F_LOOKUP_AD))
2230 2230 continue;
2231 2231
2232 2232 /*
2233 2233 * If we deferred it this time, reset for the next
2234 2234 * AD server.
2235 2235 */
2236 2236 if (req->direction & _IDMAP_F_LOOKUP_OTHER_AD) {
2237 2237 req->direction &= ~_IDMAP_F_LOOKUP_OTHER_AD;
2238 2238 continue;
2239 2239 }
2240 2240
2241 2241 /* Count number processed */
2242 2242 (*num_processed)++;
2243 2243
2244 2244 /* Reset AD lookup flag */
2245 2245 req->direction &= ~(_IDMAP_F_LOOKUP_AD);
2246 2246
2247 2247 /*
2248 2248 * If batch_start or batch_add failed then set the
2249 2249 * status of each request marked for AD lookup to
2250 2250 * that error.
2251 2251 */
2252 2252 if (retcode != IDMAP_SUCCESS) {
2253 2253 res->retcode = retcode;
2254 2254 continue;
2255 2255 }
2256 2256
2257 2257 if (res->retcode == IDMAP_ERR_NOTFOUND) {
2258 2258 /* Nothing found - remove the preset info */
2259 2259 idmap_how_clear(&res->info.how);
2260 2260 }
2261 2261
2262 2262 if (IS_ID_SID(req->id1)) {
2263 2263 if (res->retcode == IDMAP_ERR_NOTFOUND) {
2264 2264 TRACE(req, res, "Not found in AD");
2265 2265 continue;
2266 2266 }
2267 2267 if (res->retcode != IDMAP_SUCCESS) {
2268 2268 TRACE(req, res, "AD lookup error=%d",
2269 2269 res->retcode);
2270 2270 continue;
2271 2271 }
2272 2272 /* Evaluate result type */
2273 2273 switch (type) {
2274 2274 case IDMAP_USID:
2275 2275 if (res->id.idtype == IDMAP_POSIXID)
2276 2276 res->id.idtype = IDMAP_UID;
2277 2277 /*
2278 2278 * We found a user. If we got information
2279 2279 * from IDMU and we were expecting a user,
2280 2280 * copy the id.
2281 2281 */
2282 2282 if (posix_id != IDMAP_SENTINEL_PID &&
2283 2283 res->id.idtype == IDMAP_UID) {
2284 2284 res->id.idmap_id_u.uid = posix_id;
2285 2285 res->direction = IDMAP_DIRECTION_BI;
2286 2286 res->info.how.map_type =
2287 2287 IDMAP_MAP_TYPE_IDMU;
2288 2288 res->info.src = IDMAP_MAP_SRC_NEW;
2289 2289 }
2290 2290 req->id1.idtype = IDMAP_USID;
2291 2291 break;
2292 2292
2293 2293 case IDMAP_GSID:
2294 2294 if (res->id.idtype == IDMAP_POSIXID)
2295 2295 res->id.idtype = IDMAP_GID;
2296 2296 /*
2297 2297 * We found a group. If we got information
2298 2298 * from IDMU and we were expecting a group,
2299 2299 * copy the id.
2300 2300 */
2301 2301 if (posix_id != IDMAP_SENTINEL_PID &&
2302 2302 res->id.idtype == IDMAP_GID) {
2303 2303 res->id.idmap_id_u.gid = posix_id;
2304 2304 res->direction = IDMAP_DIRECTION_BI;
2305 2305 res->info.how.map_type =
2306 2306 IDMAP_MAP_TYPE_IDMU;
2307 2307 res->info.src = IDMAP_MAP_SRC_NEW;
2308 2308 }
2309 2309 req->id1.idtype = IDMAP_GSID;
2310 2310 break;
2311 2311
2312 2312 default:
2313 2313 res->retcode = IDMAP_ERR_SID;
2314 2314 break;
2315 2315 }
2316 2316 TRACE(req, res, "Found in AD");
2317 2317 if (res->retcode == IDMAP_SUCCESS &&
2318 2318 req->id1name != NULL &&
2319 2319 (req->id2name == NULL ||
2320 2320 res->id.idmap_id_u.uid == IDMAP_SENTINEL_PID) &&
2321 2321 NLDAP_MODE(res->id.idtype, state)) {
2322 2322 req->direction |= _IDMAP_F_LOOKUP_NLDAP;
2323 2323 state->nldap_nqueries++;
2324 2324 }
2325 2325 } else if (IS_ID_UID(req->id1) || IS_ID_GID(req->id1)) {
2326 2326 if (res->retcode != IDMAP_SUCCESS) {
2327 2327 if ((!(IDMAP_FATAL_ERROR(res->retcode))) &&
2328 2328 res->id.idmap_id_u.sid.prefix == NULL &&
2329 2329 req->id2name == NULL) {
2330 2330 /*
2331 2331 * If AD lookup by unixname or pid
2332 2332 * failed with non fatal error
2333 2333 * then clear the error (ie set
2334 2334 * res->retcode to success).
2335 2335 * This allows the next pass to
2336 2336 * process other mapping
2337 2337 * mechanisms for this request.
2338 2338 */
2339 2339 if (res->retcode ==
2340 2340 IDMAP_ERR_NOTFOUND) {
2341 2341 /* This is not an error */
2342 2342 res->retcode = IDMAP_SUCCESS;
2343 2343 TRACE(req, res,
2344 2344 "Not found in AD");
2345 2345 } else {
2346 2346 TRACE(req, res,
2347 2347 "AD lookup error (ignored)");
2348 2348 res->retcode = IDMAP_SUCCESS;
2349 2349 }
2350 2350 } else {
2351 2351 TRACE(req, res, "AD lookup error");
2352 2352 }
2353 2353 continue;
2354 2354 }
2355 2355 /* Evaluate result type */
2356 2356 switch (type) {
2357 2357 case IDMAP_USID:
2358 2358 case IDMAP_GSID:
2359 2359 if (res->id.idtype == IDMAP_SID)
2360 2360 res->id.idtype = type;
2361 2361 break;
2362 2362
2363 2363 default:
2364 2364 res->retcode = IDMAP_ERR_SID;
2365 2365 break;
2366 2366 }
2367 2367 TRACE(req, res, "Found in AD");
2368 2368 }
2369 2369 }
2370 2370
2371 2371 return (retcode);
2372 2372 }
2373 2373
2374 2374
2375 2375
2376 2376 /*
2377 2377 * Batch AD lookups
2378 2378 */
2379 2379 idmap_retcode
2380 2380 ad_lookup_batch(lookup_state_t *state, idmap_mapping_batch *batch,
2381 2381 idmap_ids_res *result)
2382 2382 {
2383 2383 idmap_retcode retcode;
2384 2384 int i, j;
2385 2385 idmap_mapping *req;
2386 2386 idmap_id_res *res;
2387 2387 int num_queries;
2388 2388 int num_processed;
2389 2389
2390 2390 if (state->ad_nqueries == 0)
2391 2391 return (IDMAP_SUCCESS);
2392 2392
2393 2393 for (i = 0; i < batch->idmap_mapping_batch_len; i++) {
2394 2394 req = &batch->idmap_mapping_batch_val[i];
2395 2395 res = &result->ids.ids_val[i];
2396 2396
2397 2397 /* Skip if not marked for AD lookup or already in error. */
2398 2398 if (!(req->direction & _IDMAP_F_LOOKUP_AD) ||
2399 2399 res->retcode != IDMAP_SUCCESS)
2400 2400 continue;
2401 2401
2402 2402 /* Init status */
2403 2403 res->retcode = IDMAP_ERR_RETRIABLE_NET_ERR;
2404 2404 }
2405 2405
2406 2406 RDLOCK_CONFIG();
2407 2407 num_queries = state->ad_nqueries;
2408 2408
2409 2409 if (_idmapdstate.num_gcs == 0 && _idmapdstate.num_dcs == 0) {
2410 2410 /* Case of no ADs */
2411 2411 retcode = IDMAP_ERR_NO_ACTIVEDIRECTORY;
2412 2412 for (i = 0; i < batch->idmap_mapping_batch_len; i++) {
2413 2413 req = &batch->idmap_mapping_batch_val[i];
2414 2414 res = &result->ids.ids_val[i];
2415 2415 if (!(req->direction & _IDMAP_F_LOOKUP_AD))
2416 2416 continue;
2417 2417 req->direction &= ~(_IDMAP_F_LOOKUP_AD);
2418 2418 res->retcode = IDMAP_ERR_NO_ACTIVEDIRECTORY;
2419 2419 }
2420 2420 goto out;
2421 2421 }
2422 2422
2423 2423 if (state->directory_based_mapping == DIRECTORY_MAPPING_IDMU) {
2424 2424 for (i = 0; i < _idmapdstate.num_dcs && num_queries > 0; i++) {
2425 2425
2426 2426 retcode = ad_lookup_batch_int(state, batch,
2427 2427 result, _idmapdstate.dcs[i],
2428 2428 i == 0 ? DOMAIN_IS_LOCAL|FOREST_IS_LOCAL : 0,
2429 2429 &num_processed);
2430 2430 num_queries -= num_processed;
2431 2431
2432 2432 }
2433 2433 }
2434 2434
2435 2435 for (i = 0; i < _idmapdstate.num_gcs && num_queries > 0; i++) {
2436 2436
2437 2437 retcode = ad_lookup_batch_int(state, batch, result,
2438 2438 _idmapdstate.gcs[i],
2439 2439 i == 0 ? FOREST_IS_LOCAL : 0,
2440 2440 &num_processed);
2441 2441 num_queries -= num_processed;
2442 2442
2443 2443 }
2444 2444
2445 2445 /*
2446 2446 * There are no more ADs to try. Return errors for any
2447 2447 * remaining requests.
2448 2448 */
2449 2449 if (num_queries > 0) {
2450 2450 for (j = 0; j < batch->idmap_mapping_batch_len; j++) {
2451 2451 req = &batch->idmap_mapping_batch_val[j];
2452 2452 res = &result->ids.ids_val[j];
2453 2453 if (!(req->direction & _IDMAP_F_LOOKUP_AD))
2454 2454 continue;
2455 2455 req->direction &= ~(_IDMAP_F_LOOKUP_AD);
2456 2456 res->retcode = IDMAP_ERR_DOMAIN_NOTFOUND;
2457 2457 }
2458 2458 }
2459 2459
2460 2460 out:
2461 2461 UNLOCK_CONFIG();
2462 2462
2463 2463 /* AD lookups done. Reset state->ad_nqueries and return */
2464 2464 state->ad_nqueries = 0;
2465 2465 return (retcode);
2466 2466 }
2467 2467
2468 2468 /*
2469 2469 * Convention when processing win2unix requests:
2470 2470 *
2471 2471 * Windows identity:
2472 2472 * req->id1name =
2473 2473 * winname if given otherwise winname found will be placed
2474 2474 * here.
2475 2475 * req->id1domain =
2476 2476 * windomain if given otherwise windomain found will be
2477 2477 * placed here.
2478 2478 * req->id1.idtype =
2479 2479 * Either IDMAP_SID/USID/GSID. If this is IDMAP_SID then it'll
2480 2480 * be set to IDMAP_USID/GSID depending upon whether the
2481 2481 * given SID is user or group respectively. The user/group-ness
2482 2482 * is determined either when looking up well-known SIDs table OR
2483 2483 * if the SID is found in namecache OR by ad_lookup_batch().
2484 2484 * req->id1..sid.[prefix, rid] =
2485 2485 * SID if given otherwise SID found will be placed here.
2486 2486 *
2487 2487 * Unix identity:
2488 2488 * req->id2name =
2489 2489 * unixname found will be placed here.
2490 2490 * req->id2domain =
2491 2491 * NOT USED
2492 2492 * res->id.idtype =
2493 2493 * Target type initialized from req->id2.idtype. If
2494 2494 * it is IDMAP_POSIXID then actual type (IDMAP_UID/GID) found
2495 2495 * will be placed here.
2496 2496 * res->id..[uid or gid] =
2497 2497 * UID/GID found will be placed here.
2498 2498 *
2499 2499 * Others:
2500 2500 * res->retcode =
2501 2501 * Return status for this request will be placed here.
2502 2502 * res->direction =
2503 2503 * Direction found will be placed here. Direction
2504 2504 * meaning whether the resultant mapping is valid
2505 2505 * only from win2unix or bi-directional.
2506 2506 * req->direction =
2507 2507 * INTERNAL USE. Used by idmapd to set various
2508 2508 * flags (_IDMAP_F_xxxx) to aid in processing
2509 2509 * of the request.
2510 2510 * req->id2.idtype =
2511 2511 * INTERNAL USE. Initially this is the requested target
2512 2512 * type and is used to initialize res->id.idtype.
2513 2513 * ad_lookup_batch() uses this field temporarily to store
2514 2514 * sid_type obtained by the batched AD lookups and after
2515 2515 * use resets it to IDMAP_NONE to prevent xdr from
2516 2516 * mis-interpreting the contents of req->id2.
2517 2517 * req->id2.idmap_id_u.uid =
2518 2518 * INTERNAL USE. If the AD lookup finds IDMU data
2519 2519 * (uidNumber or gidNumber, depending on the type of
2520 2520 * the entry), it's left here.
2521 2521 */
2522 2522
2523 2523 /*
2524 2524 * This function does the following:
2525 2525 * 1. Lookup well-known SIDs table.
2526 2526 * 2. Check if the given SID is a local-SID and if so extract UID/GID from it.
2527 2527 * 3. Lookup cache.
2528 2528 * 4. Check if the client does not want new mapping to be allocated
2529 2529 * in which case this pass is the final pass.
2530 2530 * 5. Set AD lookup flag if it determines that the next stage needs
2531 2531 * to do AD lookup.
2532 2532 */
2533 2533 idmap_retcode
2534 2534 sid2pid_first_pass(lookup_state_t *state, idmap_mapping *req,
2535 2535 idmap_id_res *res)
2536 2536 {
2537 2537 idmap_retcode retcode;
2538 2538 int wksid;
2539 2539
2540 2540 /* Initialize result */
2541 2541 res->id.idtype = req->id2.idtype;
2542 2542 res->id.idmap_id_u.uid = IDMAP_SENTINEL_PID;
2543 2543 res->direction = IDMAP_DIRECTION_UNDEF;
2544 2544 wksid = 0;
2545 2545
2546 2546 if (EMPTY_STRING(req->id1.idmap_id_u.sid.prefix)) {
2547 2547 /* They have to give us *something* to work with! */
2548 2548 if (req->id1name == NULL) {
2549 2549 retcode = IDMAP_ERR_ARG;
2550 2550 goto out;
2551 2551 }
2552 2552
2553 2553 /* sanitize sidprefix */
2554 2554 free(req->id1.idmap_id_u.sid.prefix);
2555 2555 req->id1.idmap_id_u.sid.prefix = NULL;
2556 2556
2557 2557 /* Allow for a fully-qualified name in the "name" parameter */
2558 2558 if (req->id1domain == NULL) {
2559 2559 char *p;
2560 2560 p = strchr(req->id1name, '@');
2561 2561 if (p != NULL) {
2562 2562 char *q;
2563 2563 q = req->id1name;
2564 2564 req->id1name = uu_strndup(q, p - req->id1name);
2565 2565 req->id1domain = strdup(p+1);
2566 2566 free(q);
2567 2567 if (req->id1name == NULL ||
2568 2568 req->id1domain == NULL) {
2569 2569 retcode = IDMAP_ERR_MEMORY;
2570 2570 goto out;
2571 2571 }
2572 2572 }
2573 2573 }
2574 2574 }
2575 2575
2576 2576 /* Lookup well-known SIDs table */
2577 2577 retcode = lookup_wksids_sid2pid(req, res, &wksid);
2578 2578 if (retcode == IDMAP_SUCCESS) {
2579 2579 /* Found a well-known account with a hardwired mapping */
2580 2580 TRACE(req, res, "Hardwired mapping");
2581 2581 goto out;
2582 2582 } else if (retcode != IDMAP_ERR_NOTFOUND) {
2583 2583 TRACE(req, res,
2584 2584 "Well-known account lookup failed, code %d", retcode);
2585 2585 goto out;
2586 2586 }
2587 2587
2588 2588 if (wksid) {
2589 2589 /* Found a well-known account, but no mapping */
2590 2590 TRACE(req, res, "Well-known account");
2591 2591 } else {
2592 2592 TRACE(req, res, "Not a well-known account");
2593 2593
2594 2594 /* Check if this is a localsid */
2595 2595 retcode = lookup_localsid2pid(req, res);
2596 2596 if (retcode == IDMAP_SUCCESS) {
2597 2597 TRACE(req, res, "Local SID");
2598 2598 goto out;
2599 2599 } else if (retcode != IDMAP_ERR_NOTFOUND) {
2600 2600 TRACE(req, res,
2601 2601 "Local SID lookup error=%d", retcode);
2602 2602 goto out;
2603 2603 }
2604 2604 TRACE(req, res, "Not a local SID");
2605 2605
2606 2606 if (ALLOW_WK_OR_LOCAL_SIDS_ONLY(req)) {
2607 2607 retcode = IDMAP_ERR_NONE_GENERATED;
2608 2608 goto out;
2609 2609 }
2610 2610 }
2611 2611
2612 2612 /*
2613 2613 * If this is a name-based request and we don't have a domain,
2614 2614 * use the default domain. Note that the well-known identity
2615 2615 * cases will have supplied a SID prefix already, and that we
2616 2616 * don't (yet?) support looking up a local user through a Windows
2617 2617 * style name.
2618 2618 */
2619 2619 if (req->id1.idmap_id_u.sid.prefix == NULL &&
2620 2620 req->id1name != NULL && req->id1domain == NULL) {
2621 2621 if (state->defdom == NULL) {
2622 2622 retcode = IDMAP_ERR_DOMAIN_NOTFOUND;
2623 2623 goto out;
2624 2624 }
2625 2625 req->id1domain = strdup(state->defdom);
2626 2626 if (req->id1domain == NULL) {
2627 2627 retcode = IDMAP_ERR_MEMORY;
2628 2628 goto out;
2629 2629 }
2630 2630 TRACE(req, res, "Added default domain");
2631 2631 }
2632 2632
2633 2633 /* Lookup cache */
2634 2634 retcode = lookup_cache_sid2pid(state->cache, req, res);
2635 2635 if (retcode == IDMAP_SUCCESS) {
2636 2636 TRACE(req, res, "Found in mapping cache");
2637 2637 goto out;
2638 2638 } else if (retcode != IDMAP_ERR_NOTFOUND) {
2639 2639 TRACE(req, res, "Mapping cache lookup error=%d", retcode);
2640 2640 goto out;
2641 2641 }
2642 2642 TRACE(req, res, "Not found in mapping cache");
2643 2643
2644 2644 if (DO_NOT_ALLOC_NEW_ID_MAPPING(req) || AVOID_NAMESERVICE(req)) {
2645 2645 retcode = IDMAP_ERR_NONE_GENERATED;
2646 2646 goto out;
2647 2647 }
2648 2648
2649 2649 /*
2650 2650 * Failed to find non-expired entry in cache. Next step is
2651 2651 * to determine if this request needs to be batched for AD lookup.
2652 2652 *
2653 2653 * At this point we have either sid or winname or both. If we don't
2654 2654 * have both then lookup name_cache for the sid or winname
2655 2655 * whichever is missing. If not found then this request will be
2656 2656 * batched for AD lookup.
2657 2657 */
2658 2658 retcode = lookup_name_cache(state->cache, req, res);
2659 2659 if (retcode == IDMAP_SUCCESS) {
2660 2660 if (res->id.idtype == IDMAP_POSIXID) {
2661 2661 if (req->id1.idtype == IDMAP_USID)
2662 2662 res->id.idtype = IDMAP_UID;
2663 2663 else
2664 2664 res->id.idtype = IDMAP_GID;
2665 2665 }
2666 2666 } else if (retcode != IDMAP_ERR_NOTFOUND)
2667 2667 goto out;
2668 2668
2669 2669 if (_idmapdstate.cfg->pgcfg.use_lsa &&
2670 2670 _idmapdstate.cfg->pgcfg.domain_name != NULL) {
2671 2671 /*
2672 2672 * If we don't have both name and SID, try looking up the
2673 2673 * entry with LSA.
2674 2674 */
2675 2675 if (req->id1.idmap_id_u.sid.prefix != NULL &&
2676 2676 req->id1name == NULL) {
2677 2677
2678 2678 retcode = lookup_lsa_by_sid(
2679 2679 req->id1.idmap_id_u.sid.prefix,
2680 2680 req->id1.idmap_id_u.sid.rid,
2681 2681 &req->id1name, &req->id1domain, &req->id1.idtype);
2682 2682 if (retcode == IDMAP_SUCCESS) {
2683 2683 TRACE(req, res, "Found with LSA");
2684 2684 } else if (retcode == IDMAP_ERR_NOTFOUND) {
2685 2685 TRACE(req, res, "Not found with LSA");
2686 2686 } else {
2687 2687 TRACE(req, res, "LSA error %d", retcode);
2688 2688 goto out;
2689 2689 }
2690 2690
2691 2691 } else if (req->id1name != NULL &&
2692 2692 req->id1.idmap_id_u.sid.prefix == NULL) {
2693 2693 char *canonname;
2694 2694 char *canondomain;
2695 2695
2696 2696 retcode = lookup_lsa_by_name(
2697 2697 req->id1name, req->id1domain,
2698 2698 &req->id1.idmap_id_u.sid.prefix,
2699 2699 &req->id1.idmap_id_u.sid.rid,
2700 2700 &canonname, &canondomain,
2701 2701 &req->id1.idtype);
2702 2702 if (retcode == IDMAP_SUCCESS) {
2703 2703 free(req->id1name);
2704 2704 req->id1name = canonname;
2705 2705 free(req->id1domain);
2706 2706 req->id1domain = canondomain;
2707 2707 TRACE(req, res, "Found with LSA");
2708 2708 } else if (retcode == IDMAP_ERR_NOTFOUND) {
2709 2709 TRACE(req, res, "Not found with LSA");
2710 2710 } else {
2711 2711 TRACE(req, res, "LSA error %d", retcode);
2712 2712 goto out;
2713 2713 }
2714 2714 }
2715 2715 }
2716 2716
2717 2717 /*
2718 2718 * Set the flag to indicate that we are not done yet so that
2719 2719 * subsequent passes considers this request for name-based
2720 2720 * mapping and ephemeral mapping.
2721 2721 */
2722 2722 state->sid2pid_done = FALSE;
2723 2723 req->direction |= _IDMAP_F_NOTDONE;
2724 2724
2725 2725 /*
2726 2726 * Even if we have both sid and winname, we still may need to batch
2727 2727 * this request for AD lookup if we don't have unixname and
2728 2728 * directory-based name mapping (AD or mixed) is enabled.
2729 2729 * We avoid AD lookup for well-known SIDs because they don't have
2730 2730 * regular AD objects.
2731 2731 */
2732 2732 if (retcode != IDMAP_SUCCESS ||
2733 2733 (!wksid && req->id2name == NULL &&
2734 2734 AD_OR_MIXED_MODE(res->id.idtype, state)) ||
2735 2735 (!wksid && res->id.idmap_id_u.uid == IDMAP_SENTINEL_PID &&
2736 2736 state->directory_based_mapping == DIRECTORY_MAPPING_IDMU)) {
2737 2737 retcode = IDMAP_SUCCESS;
2738 2738 req->direction |= _IDMAP_F_LOOKUP_AD;
2739 2739 state->ad_nqueries++;
2740 2740 } else if (NLDAP_MODE(res->id.idtype, state)) {
2741 2741 req->direction |= _IDMAP_F_LOOKUP_NLDAP;
2742 2742 state->nldap_nqueries++;
2743 2743 }
2744 2744
2745 2745
2746 2746 out:
2747 2747 res->retcode = idmap_stat4prot(retcode);
2748 2748 /*
2749 2749 * If we are done and there was an error then set fallback pid
2750 2750 * in the result.
2751 2751 */
2752 2752 if (ARE_WE_DONE(req->direction) && res->retcode != IDMAP_SUCCESS)
2753 2753 res->id.idmap_id_u.uid = UID_NOBODY;
2754 2754 return (retcode);
2755 2755 }
2756 2756
2757 2757 /*
2758 2758 * Generate SID using the following convention
2759 2759 * <machine-sid-prefix>-<1000 + uid>
2760 2760 * <machine-sid-prefix>-<2^31 + gid>
2761 2761 */
2762 2762 static
2763 2763 idmap_retcode
2764 2764 generate_localsid(idmap_mapping *req, idmap_id_res *res, int is_user,
2765 2765 int fallback)
2766 2766 {
2767 2767 free(res->id.idmap_id_u.sid.prefix);
2768 2768 res->id.idmap_id_u.sid.prefix = NULL;
2769 2769
2770 2770 /*
2771 2771 * Diagonal mapping for localSIDs not supported because of the
2772 2772 * way we generate localSIDs.
2773 2773 */
2774 2774 if (is_user && res->id.idtype == IDMAP_GSID)
2775 2775 return (IDMAP_ERR_NOTGROUP);
2776 2776 if (!is_user && res->id.idtype == IDMAP_USID)
2777 2777 return (IDMAP_ERR_NOTUSER);
2778 2778
2779 2779 /* Skip 1000 UIDs */
2780 2780 if (is_user &&
2781 2781 req->id1.idmap_id_u.uid + LOCALRID_UID_MIN > LOCALRID_UID_MAX)
2782 2782 return (IDMAP_ERR_NOMAPPING);
2783 2783
2784 2784 RDLOCK_CONFIG();
2785 2785 /*
2786 2786 * machine_sid is never NULL because if it is we won't be here.
2787 2787 * No need to assert because strdup(NULL) will core anyways.
2788 2788 */
2789 2789 res->id.idmap_id_u.sid.prefix =
2790 2790 strdup(_idmapdstate.cfg->pgcfg.machine_sid);
2791 2791 if (res->id.idmap_id_u.sid.prefix == NULL) {
2792 2792 UNLOCK_CONFIG();
2793 2793 idmapdlog(LOG_ERR, "Out of memory");
2794 2794 return (IDMAP_ERR_MEMORY);
2795 2795 }
2796 2796 UNLOCK_CONFIG();
2797 2797 res->id.idmap_id_u.sid.rid =
2798 2798 (is_user) ? req->id1.idmap_id_u.uid + LOCALRID_UID_MIN :
2799 2799 req->id1.idmap_id_u.gid + LOCALRID_GID_MIN;
2800 2800 res->direction = IDMAP_DIRECTION_BI;
2801 2801 if (res->id.idtype == IDMAP_SID)
2802 2802 res->id.idtype = is_user ? IDMAP_USID : IDMAP_GSID;
2803 2803
2804 2804 if (!fallback) {
2805 2805 res->info.how.map_type = IDMAP_MAP_TYPE_LOCAL_SID;
2806 2806 res->info.src = IDMAP_MAP_SRC_ALGORITHMIC;
2807 2807 }
2808 2808
2809 2809 /*
2810 2810 * Don't update name_cache because local sids don't have
2811 2811 * valid windows names.
2812 2812 */
2813 2813 req->direction |= _IDMAP_F_DONT_UPDATE_NAMECACHE;
2814 2814 return (IDMAP_SUCCESS);
2815 2815 }
2816 2816
2817 2817 static
2818 2818 idmap_retcode
2819 2819 lookup_localsid2pid(idmap_mapping *req, idmap_id_res *res)
2820 2820 {
2821 2821 char *sidprefix;
2822 2822 uint32_t rid;
2823 2823 int s;
2824 2824
2825 2825 /*
2826 2826 * If the sidprefix == localsid then UID = last RID - 1000 or
2827 2827 * GID = last RID - 2^31.
2828 2828 */
2829 2829 if ((sidprefix = req->id1.idmap_id_u.sid.prefix) == NULL)
2830 2830 /* This means we are looking up by winname */
2831 2831 return (IDMAP_ERR_NOTFOUND);
2832 2832 rid = req->id1.idmap_id_u.sid.rid;
2833 2833
2834 2834 RDLOCK_CONFIG();
2835 2835 s = (_idmapdstate.cfg->pgcfg.machine_sid) ?
2836 2836 strcasecmp(sidprefix, _idmapdstate.cfg->pgcfg.machine_sid) : 1;
2837 2837 UNLOCK_CONFIG();
2838 2838
2839 2839 /*
2840 2840 * If the given sidprefix does not match machine_sid then this is
2841 2841 * not a local SID.
2842 2842 */
2843 2843 if (s != 0)
2844 2844 return (IDMAP_ERR_NOTFOUND);
2845 2845
2846 2846 switch (res->id.idtype) {
2847 2847 case IDMAP_UID:
2848 2848 if (rid < LOCALRID_UID_MIN || rid > LOCALRID_UID_MAX)
2849 2849 return (IDMAP_ERR_ARG);
2850 2850 res->id.idmap_id_u.uid = rid - LOCALRID_UID_MIN;
2851 2851 break;
2852 2852 case IDMAP_GID:
2853 2853 if (rid < LOCALRID_GID_MIN)
2854 2854 return (IDMAP_ERR_ARG);
2855 2855 res->id.idmap_id_u.gid = rid - LOCALRID_GID_MIN;
2856 2856 break;
2857 2857 case IDMAP_POSIXID:
2858 2858 if (rid >= LOCALRID_GID_MIN) {
2859 2859 res->id.idmap_id_u.gid = rid - LOCALRID_GID_MIN;
2860 2860 res->id.idtype = IDMAP_GID;
2861 2861 } else if (rid >= LOCALRID_UID_MIN) {
2862 2862 res->id.idmap_id_u.uid = rid - LOCALRID_UID_MIN;
2863 2863 res->id.idtype = IDMAP_UID;
2864 2864 } else {
2865 2865 return (IDMAP_ERR_ARG);
2866 2866 }
2867 2867 break;
2868 2868 default:
2869 2869 return (IDMAP_ERR_NOTSUPPORTED);
2870 2870 }
2871 2871 res->info.how.map_type = IDMAP_MAP_TYPE_LOCAL_SID;
2872 2872 res->info.src = IDMAP_MAP_SRC_ALGORITHMIC;
2873 2873 return (IDMAP_SUCCESS);
2874 2874 }
2875 2875
2876 2876 /*
2877 2877 * Name service lookup by unixname to get pid
2878 2878 */
2879 2879 static
2880 2880 idmap_retcode
2881 2881 ns_lookup_byname(const char *name, const char *lower_name, idmap_id *id)
2882 2882 {
2883 2883 struct passwd pwd, *pwdp;
2884 2884 struct group grp, *grpp;
2885 2885 char *buf;
2886 2886 static size_t pwdbufsiz = 0;
2887 2887 static size_t grpbufsiz = 0;
2888 2888
2889 2889 switch (id->idtype) {
2890 2890 case IDMAP_UID:
2891 2891 if (pwdbufsiz == 0)
2892 2892 pwdbufsiz = sysconf(_SC_GETPW_R_SIZE_MAX);
2893 2893 buf = alloca(pwdbufsiz);
2894 2894 pwdp = getpwnam_r(name, &pwd, buf, pwdbufsiz);
2895 2895 if (pwdp == NULL && errno == 0 && lower_name != NULL &&
2896 2896 name != lower_name && strcmp(name, lower_name) != 0)
2897 2897 pwdp = getpwnam_r(lower_name, &pwd, buf, pwdbufsiz);
2898 2898 if (pwdp == NULL) {
2899 2899 if (errno == 0)
2900 2900 return (IDMAP_ERR_NOTFOUND);
2901 2901 else
2902 2902 return (IDMAP_ERR_INTERNAL);
2903 2903 }
2904 2904 id->idmap_id_u.uid = pwd.pw_uid;
2905 2905 break;
2906 2906 case IDMAP_GID:
2907 2907 if (grpbufsiz == 0)
2908 2908 grpbufsiz = sysconf(_SC_GETGR_R_SIZE_MAX);
2909 2909 buf = alloca(grpbufsiz);
2910 2910 grpp = getgrnam_r(name, &grp, buf, grpbufsiz);
2911 2911 if (grpp == NULL && errno == 0 && lower_name != NULL &&
2912 2912 name != lower_name && strcmp(name, lower_name) != 0)
2913 2913 grpp = getgrnam_r(lower_name, &grp, buf, grpbufsiz);
2914 2914 if (grpp == NULL) {
2915 2915 if (errno == 0)
2916 2916 return (IDMAP_ERR_NOTFOUND);
2917 2917 else
2918 2918 return (IDMAP_ERR_INTERNAL);
2919 2919 }
2920 2920 id->idmap_id_u.gid = grp.gr_gid;
2921 2921 break;
2922 2922 default:
2923 2923 return (IDMAP_ERR_ARG);
2924 2924 }
2925 2925 return (IDMAP_SUCCESS);
2926 2926 }
2927 2927
2928 2928
2929 2929 /*
2930 2930 * Name service lookup by pid to get unixname
2931 2931 */
2932 2932 static
2933 2933 idmap_retcode
2934 2934 ns_lookup_bypid(uid_t pid, int is_user, char **unixname)
2935 2935 {
2936 2936 struct passwd pwd;
2937 2937 struct group grp;
2938 2938 char *buf;
2939 2939 static size_t pwdbufsiz = 0;
2940 2940 static size_t grpbufsiz = 0;
2941 2941
2942 2942 if (is_user) {
2943 2943 if (pwdbufsiz == 0)
2944 2944 pwdbufsiz = sysconf(_SC_GETPW_R_SIZE_MAX);
2945 2945 buf = alloca(pwdbufsiz);
2946 2946 errno = 0;
2947 2947 if (getpwuid_r(pid, &pwd, buf, pwdbufsiz) == NULL) {
2948 2948 if (errno == 0)
2949 2949 return (IDMAP_ERR_NOTFOUND);
2950 2950 else
2951 2951 return (IDMAP_ERR_INTERNAL);
2952 2952 }
2953 2953 *unixname = strdup(pwd.pw_name);
2954 2954 } else {
2955 2955 if (grpbufsiz == 0)
2956 2956 grpbufsiz = sysconf(_SC_GETGR_R_SIZE_MAX);
2957 2957 buf = alloca(grpbufsiz);
2958 2958 errno = 0;
2959 2959 if (getgrgid_r(pid, &grp, buf, grpbufsiz) == NULL) {
2960 2960 if (errno == 0)
2961 2961 return (IDMAP_ERR_NOTFOUND);
2962 2962 else
2963 2963 return (IDMAP_ERR_INTERNAL);
2964 2964 }
2965 2965 *unixname = strdup(grp.gr_name);
2966 2966 }
2967 2967 if (*unixname == NULL)
2968 2968 return (IDMAP_ERR_MEMORY);
2969 2969 return (IDMAP_SUCCESS);
2970 2970 }
2971 2971
2972 2972 /*
2973 2973 * Name-based mapping
2974 2974 *
2975 2975 * Case 1: If no rule matches do ephemeral
2976 2976 *
2977 2977 * Case 2: If rule matches and unixname is "" then return no mapping.
2978 2978 *
2979 2979 * Case 3: If rule matches and unixname is specified then lookup name
2980 2980 * service using the unixname. If unixname not found then return no mapping.
2981 2981 *
2982 2982 * Case 4: If rule matches and unixname is * then lookup name service
2983 2983 * using winname as the unixname. If unixname not found then process
2984 2984 * other rules using the lookup order. If no other rule matches then do
2985 2985 * ephemeral. Otherwise, based on the matched rule do Case 2 or 3 or 4.
2986 2986 * This allows us to specify a fallback unixname per _domain_ or no mapping
2987 2987 * instead of the default behaviour of doing ephemeral mapping.
2988 2988 *
2989 2989 * Example 1:
2990 2990 * *@sfbay == *
2991 2991 * If looking up windows users foo@sfbay and foo does not exists in
2992 2992 * the name service then foo@sfbay will be mapped to an ephemeral id.
2993 2993 *
2994 2994 * Example 2:
2995 2995 * *@sfbay == *
2996 2996 * *@sfbay => guest
2997 2997 * If looking up windows users foo@sfbay and foo does not exists in
2998 2998 * the name service then foo@sfbay will be mapped to guest.
2999 2999 *
3000 3000 * Example 3:
3001 3001 * *@sfbay == *
3002 3002 * *@sfbay => ""
3003 3003 * If looking up windows users foo@sfbay and foo does not exists in
3004 3004 * the name service then we will return no mapping for foo@sfbay.
3005 3005 *
3006 3006 */
3007 3007 static
3008 3008 idmap_retcode
3009 3009 name_based_mapping_sid2pid(lookup_state_t *state,
3010 3010 idmap_mapping *req, idmap_id_res *res)
3011 3011 {
3012 3012 const char *unixname, *windomain;
3013 3013 char *sql = NULL, *errmsg = NULL, *lower_winname = NULL;
3014 3014 idmap_retcode retcode;
3015 3015 char *end, *lower_unixname, *winname;
3016 3016 const char **values;
3017 3017 sqlite_vm *vm = NULL;
3018 3018 int ncol, r, is_user, is_wuser;
3019 3019 idmap_namerule *rule = &res->info.how.idmap_how_u.rule;
3020 3020 int direction;
3021 3021 const char *me = "name_based_mapping_sid2pid";
3022 3022
3023 3023 assert(req->id1name != NULL); /* We have winname */
3024 3024 assert(req->id2name == NULL); /* We don't have unixname */
3025 3025
3026 3026 winname = req->id1name;
3027 3027 windomain = req->id1domain;
3028 3028
3029 3029 switch (req->id1.idtype) {
3030 3030 case IDMAP_USID:
3031 3031 is_wuser = 1;
3032 3032 break;
3033 3033 case IDMAP_GSID:
3034 3034 is_wuser = 0;
3035 3035 break;
3036 3036 default:
3037 3037 idmapdlog(LOG_ERR, "%s: Unable to determine if the "
3038 3038 "given Windows id is user or group.", me);
3039 3039 return (IDMAP_ERR_INTERNAL);
3040 3040 }
3041 3041
3042 3042 switch (res->id.idtype) {
3043 3043 case IDMAP_UID:
3044 3044 is_user = 1;
3045 3045 break;
3046 3046 case IDMAP_GID:
3047 3047 is_user = 0;
3048 3048 break;
3049 3049 case IDMAP_POSIXID:
3050 3050 is_user = is_wuser;
3051 3051 res->id.idtype = is_user ? IDMAP_UID : IDMAP_GID;
3052 3052 break;
3053 3053 }
3054 3054
3055 3055 if (windomain == NULL)
3056 3056 windomain = "";
3057 3057
3058 3058 if ((lower_winname = tolower_u8(winname)) == NULL)
3059 3059 lower_winname = winname; /* hope for the best */
3060 3060 sql = sqlite_mprintf(
3061 3061 "SELECT unixname, u2w_order, winname_display, windomain, is_nt4 "
3062 3062 "FROM namerules WHERE "
3063 3063 "w2u_order > 0 AND is_user = %d AND is_wuser = %d AND "
3064 3064 "(winname = %Q OR winname = '*') AND "
3065 3065 "(windomain = %Q OR windomain = '*') "
3066 3066 "ORDER BY w2u_order ASC;",
3067 3067 is_user, is_wuser, lower_winname, windomain);
3068 3068 if (sql == NULL) {
3069 3069 idmapdlog(LOG_ERR, "Out of memory");
3070 3070 retcode = IDMAP_ERR_MEMORY;
3071 3071 goto out;
3072 3072 }
3073 3073
3074 3074 if (sqlite_compile(state->db, sql, NULL, &vm, &errmsg) != SQLITE_OK) {
3075 3075 retcode = IDMAP_ERR_INTERNAL;
3076 3076 idmapdlog(LOG_ERR, "%s: database error (%s)", me,
3077 3077 CHECK_NULL(errmsg));
3078 3078 sqlite_freemem(errmsg);
3079 3079 goto out;
3080 3080 }
3081 3081
3082 3082 for (;;) {
3083 3083 r = sqlite_step(vm, &ncol, &values, NULL);
3084 3084 assert(r != SQLITE_LOCKED && r != SQLITE_BUSY);
3085 3085
3086 3086 if (r == SQLITE_ROW) {
3087 3087 if (ncol < 5) {
3088 3088 retcode = IDMAP_ERR_INTERNAL;
3089 3089 goto out;
3090 3090 }
3091 3091
3092 3092 TRACE(req, res, "Matching rule: %s@%s -> %s",
3093 3093 values[2] == NULL ? "(null)" : values[2],
3094 3094 values[3] == NULL ? "(null)" : values[3],
3095 3095 values[0] == NULL ? "(null)" : values[0]);
3096 3096
3097 3097 if (values[0] == NULL) {
3098 3098 retcode = IDMAP_ERR_INTERNAL;
3099 3099 goto out;
3100 3100 }
3101 3101
3102 3102 if (values[1] != NULL)
3103 3103 direction =
3104 3104 (strtol(values[1], &end, 10) == 0)?
3105 3105 IDMAP_DIRECTION_W2U:IDMAP_DIRECTION_BI;
3106 3106 else
3107 3107 direction = IDMAP_DIRECTION_W2U;
3108 3108
3109 3109 if (EMPTY_NAME(values[0])) {
3110 3110 TRACE(req, res, "Mapping inhibited");
3111 3111 idmap_namerule_set(rule, values[3], values[2],
3112 3112 values[0], is_user, is_wuser,
3113 3113 strtol(values[4], &end, 10),
3114 3114 direction);
3115 3115 retcode = IDMAP_ERR_NOMAPPING;
3116 3116 goto out;
3117 3117 }
3118 3118
3119 3119 if (values[0][0] == '*') {
3120 3120 unixname = winname;
3121 3121 lower_unixname = lower_winname;
3122 3122 } else {
3123 3123 unixname = values[0];
3124 3124 lower_unixname = NULL;
3125 3125 }
3126 3126
3127 3127 retcode = ns_lookup_byname(unixname, lower_unixname,
3128 3128 &res->id);
3129 3129 if (retcode == IDMAP_SUCCESS) {
3130 3130 break;
3131 3131 } else if (retcode == IDMAP_ERR_NOTFOUND) {
3132 3132 if (values[0][0] == '*') {
3133 3133 TRACE(req, res,
3134 3134 "%s not found, continuing",
3135 3135 unixname);
3136 3136 /* Case 4 */
3137 3137 continue;
3138 3138 } else {
3139 3139 TRACE(req, res,
3140 3140 "%s not found, error", unixname);
3141 3141 /* Case 3 */
3142 3142 idmap_namerule_set(rule, values[3],
3143 3143 values[2], values[0], is_user,
3144 3144 is_wuser,
3145 3145 strtol(values[4], &end, 10),
3146 3146 direction);
3147 3147 retcode = IDMAP_ERR_NOMAPPING;
3148 3148 }
3149 3149 } else {
3150 3150 TRACE(req, res, "Looking up %s error=%d",
3151 3151 unixname, retcode);
3152 3152 }
3153 3153 goto out;
3154 3154 } else if (r == SQLITE_DONE) {
3155 3155 TRACE(req, res, "No matching rule");
3156 3156 retcode = IDMAP_ERR_NOTFOUND;
3157 3157 goto out;
3158 3158 } else {
3159 3159 (void) sqlite_finalize(vm, &errmsg);
3160 3160 vm = NULL;
3161 3161 idmapdlog(LOG_ERR, "%s: database error (%s)", me,
3162 3162 CHECK_NULL(errmsg));
3163 3163 sqlite_freemem(errmsg);
3164 3164 retcode = IDMAP_ERR_INTERNAL;
3165 3165 goto out;
3166 3166 }
3167 3167 }
3168 3168
3169 3169 /* Found */
3170 3170
3171 3171 if (values[1] != NULL)
3172 3172 res->direction =
3173 3173 (strtol(values[1], &end, 10) == 0)?
3174 3174 IDMAP_DIRECTION_W2U:IDMAP_DIRECTION_BI;
3175 3175 else
3176 3176 res->direction = IDMAP_DIRECTION_W2U;
3177 3177
3178 3178 req->id2name = strdup(unixname);
3179 3179 if (req->id2name == NULL) {
3180 3180 retcode = IDMAP_ERR_MEMORY;
3181 3181 goto out;
3182 3182 }
3183 3183 TRACE(req, res, "UNIX name found");
3184 3184
3185 3185 idmap_namerule_set(rule, values[3], values[2],
3186 3186 values[0], is_user, is_wuser, strtol(values[4], &end, 10),
3187 3187 res->direction);
3188 3188
3189 3189 out:
3190 3190 if (retcode != IDMAP_SUCCESS &&
3191 3191 retcode != IDMAP_ERR_NOTFOUND &&
3192 3192 retcode != IDMAP_ERR_NOMAPPING) {
3193 3193 TRACE(req, res, "Rule processing error, code=%d", retcode);
3194 3194 }
3195 3195
3196 3196 if (sql != NULL)
3197 3197 sqlite_freemem(sql);
3198 3198
3199 3199 if (retcode != IDMAP_ERR_NOTFOUND) {
3200 3200 res->info.how.map_type = IDMAP_MAP_TYPE_RULE_BASED;
3201 3201 res->info.src = IDMAP_MAP_SRC_NEW;
3202 3202 }
3203 3203
3204 3204 if (lower_winname != NULL && lower_winname != winname)
3205 3205 free(lower_winname);
3206 3206 if (vm != NULL)
3207 3207 (void) sqlite_finalize(vm, NULL);
3208 3208 return (retcode);
3209 3209 }
3210 3210
3211 3211 static
3212 3212 int
3213 3213 get_next_eph_uid(uid_t *next_uid)
3214 3214 {
3215 3215 uid_t uid;
3216 3216 gid_t gid;
3217 3217 int err;
3218 3218
3219 3219 *next_uid = (uid_t)-1;
3220 3220 uid = _idmapdstate.next_uid++;
3221 3221 if (uid >= _idmapdstate.limit_uid) {
3222 3222 if ((err = allocids(0, 8192, &uid, 0, &gid)) != 0)
3223 3223 return (err);
3224 3224
3225 3225 _idmapdstate.limit_uid = uid + 8192;
3226 3226 _idmapdstate.next_uid = uid;
3227 3227 }
3228 3228 *next_uid = uid;
3229 3229
3230 3230 return (0);
3231 3231 }
3232 3232
3233 3233 static
3234 3234 int
3235 3235 get_next_eph_gid(gid_t *next_gid)
3236 3236 {
3237 3237 uid_t uid;
3238 3238 gid_t gid;
3239 3239 int err;
3240 3240
3241 3241 *next_gid = (uid_t)-1;
3242 3242 gid = _idmapdstate.next_gid++;
3243 3243 if (gid >= _idmapdstate.limit_gid) {
3244 3244 if ((err = allocids(0, 0, &uid, 8192, &gid)) != 0)
3245 3245 return (err);
3246 3246
3247 3247 _idmapdstate.limit_gid = gid + 8192;
3248 3248 _idmapdstate.next_gid = gid;
3249 3249 }
3250 3250 *next_gid = gid;
3251 3251
3252 3252 return (0);
3253 3253 }
3254 3254
3255 3255 static
3256 3256 int
3257 3257 gethash(const char *str, uint32_t num, uint_t htsize)
3258 3258 {
3259 3259 uint_t hval, i, len;
3260 3260
3261 3261 if (str == NULL)
3262 3262 return (0);
3263 3263 for (len = strlen(str), hval = 0, i = 0; i < len; i++) {
3264 3264 hval += str[i];
3265 3265 hval += (hval << 10);
3266 3266 hval ^= (hval >> 6);
3267 3267 }
3268 3268 for (str = (const char *)&num, i = 0; i < sizeof (num); i++) {
3269 3269 hval += str[i];
3270 3270 hval += (hval << 10);
3271 3271 hval ^= (hval >> 6);
3272 3272 }
3273 3273 hval += (hval << 3);
3274 3274 hval ^= (hval >> 11);
3275 3275 hval += (hval << 15);
3276 3276 return (hval % htsize);
3277 3277 }
3278 3278
3279 3279 static
3280 3280 int
3281 3281 get_from_sid_history(lookup_state_t *state, const char *prefix, uint32_t rid,
3282 3282 uid_t *pid)
3283 3283 {
3284 3284 uint_t next, key;
3285 3285 uint_t htsize = state->sid_history_size;
3286 3286 idmap_sid *sid;
3287 3287
3288 3288 next = gethash(prefix, rid, htsize);
3289 3289 while (next != htsize) {
3290 3290 key = state->sid_history[next].key;
3291 3291 if (key == htsize)
3292 3292 return (0);
3293 3293 sid = &state->batch->idmap_mapping_batch_val[key].id1.
3294 3294 idmap_id_u.sid;
3295 3295 if (sid->rid == rid && strcmp(sid->prefix, prefix) == 0) {
3296 3296 *pid = state->result->ids.ids_val[key].id.
3297 3297 idmap_id_u.uid;
3298 3298 return (1);
3299 3299 }
3300 3300 next = state->sid_history[next].next;
3301 3301 }
3302 3302 return (0);
3303 3303 }
3304 3304
3305 3305 static
3306 3306 void
3307 3307 add_to_sid_history(lookup_state_t *state, const char *prefix, uint32_t rid)
3308 3308 {
3309 3309 uint_t hash, next;
3310 3310 uint_t htsize = state->sid_history_size;
3311 3311
3312 3312 hash = next = gethash(prefix, rid, htsize);
3313 3313 while (state->sid_history[next].key != htsize) {
3314 3314 next++;
3315 3315 next %= htsize;
3316 3316 }
3317 3317 state->sid_history[next].key = state->curpos;
3318 3318 if (hash == next)
3319 3319 return;
3320 3320 state->sid_history[next].next = state->sid_history[hash].next;
3321 3321 state->sid_history[hash].next = next;
3322 3322 }
3323 3323
3324 3324 void
3325 3325 cleanup_lookup_state(lookup_state_t *state)
3326 3326 {
3327 3327 free(state->sid_history);
3328 3328 free(state->ad_unixuser_attr);
3329 3329 free(state->ad_unixgroup_attr);
3330 3330 free(state->nldap_winname_attr);
3331 3331 free(state->defdom);
3332 3332 }
3333 3333
3334 3334 /* ARGSUSED */
3335 3335 static
3336 3336 idmap_retcode
3337 3337 dynamic_ephemeral_mapping(lookup_state_t *state,
3338 3338 idmap_mapping *req, idmap_id_res *res)
3339 3339 {
3340 3340
3341 3341 uid_t next_pid;
3342 3342
3343 3343 res->direction = IDMAP_DIRECTION_BI;
3344 3344
3345 3345 if (IDMAP_ID_IS_EPHEMERAL(res->id.idmap_id_u.uid)) {
3346 3346 res->info.how.map_type = IDMAP_MAP_TYPE_EPHEMERAL;
3347 3347 res->info.src = IDMAP_MAP_SRC_CACHE;
3348 3348 return (IDMAP_SUCCESS);
3349 3349 }
3350 3350
3351 3351 if (state->sid_history != NULL &&
3352 3352 get_from_sid_history(state, req->id1.idmap_id_u.sid.prefix,
3353 3353 req->id1.idmap_id_u.sid.rid, &next_pid)) {
3354 3354 res->id.idmap_id_u.uid = next_pid;
3355 3355 res->info.how.map_type = IDMAP_MAP_TYPE_EPHEMERAL;
3356 3356 res->info.src = IDMAP_MAP_SRC_NEW;
3357 3357 return (IDMAP_SUCCESS);
3358 3358 }
3359 3359
3360 3360 if (res->id.idtype == IDMAP_UID) {
3361 3361 if (get_next_eph_uid(&next_pid) != 0)
3362 3362 return (IDMAP_ERR_INTERNAL);
3363 3363 res->id.idmap_id_u.uid = next_pid;
3364 3364 } else {
3365 3365 if (get_next_eph_gid(&next_pid) != 0)
3366 3366 return (IDMAP_ERR_INTERNAL);
3367 3367 res->id.idmap_id_u.gid = next_pid;
3368 3368 }
3369 3369
3370 3370 res->info.how.map_type = IDMAP_MAP_TYPE_EPHEMERAL;
3371 3371 res->info.src = IDMAP_MAP_SRC_NEW;
3372 3372 if (state->sid_history != NULL)
3373 3373 add_to_sid_history(state, req->id1.idmap_id_u.sid.prefix,
3374 3374 req->id1.idmap_id_u.sid.rid);
3375 3375
3376 3376 return (IDMAP_SUCCESS);
3377 3377 }
3378 3378
3379 3379 idmap_retcode
3380 3380 sid2pid_second_pass(lookup_state_t *state,
3381 3381 idmap_mapping *req, idmap_id_res *res)
3382 3382 {
3383 3383 idmap_retcode retcode;
3384 3384 idmap_retcode retcode2;
3385 3385
3386 3386 /* Check if second pass is needed */
3387 3387 if (ARE_WE_DONE(req->direction))
3388 3388 return (res->retcode);
3389 3389
3390 3390 /* Get status from previous pass */
3391 3391 retcode = res->retcode;
3392 3392 if (retcode != IDMAP_SUCCESS && state->eph_map_unres_sids &&
3393 3393 !EMPTY_STRING(req->id1.idmap_id_u.sid.prefix) &&
3394 3394 EMPTY_STRING(req->id1name)) {
3395 3395 /*
3396 3396 * We are asked to map an unresolvable SID to a UID or
3397 3397 * GID, but, which? We'll treat all unresolvable SIDs
3398 3398 * as users unless the caller specified which of a UID
3399 3399 * or GID they want.
3400 3400 */
3401 3401 if (req->id1.idtype == IDMAP_SID)
3402 3402 req->id1.idtype = IDMAP_USID;
3403 3403 if (res->id.idtype == IDMAP_POSIXID) {
3404 3404 res->id.idtype = IDMAP_UID;
3405 3405 TRACE(req, res, "Assume unresolvable SID is user");
3406 3406 } else if (res->id.idtype == IDMAP_UID) {
3407 3407 TRACE(req, res, "Must map unresolvable SID to user");
3408 3408 } else if (res->id.idtype == IDMAP_GID) {
3409 3409 TRACE(req, res, "Must map unresolvable SID to group");
3410 3410 }
3411 3411 goto do_eph;
3412 3412 }
3413 3413 if (retcode != IDMAP_SUCCESS)
3414 3414 goto out;
3415 3415
3416 3416 /*
3417 3417 * There are two ways we might get here with a Posix ID:
3418 3418 * - It could be from an expired ephemeral cache entry.
3419 3419 * - It could be from IDMU.
3420 3420 * If it's from IDMU, we need to look up the name, for name-based
3421 3421 * requests and the cache.
3422 3422 */
3423 3423 if (!IDMAP_ID_IS_EPHEMERAL(res->id.idmap_id_u.uid) &&
3424 3424 res->id.idmap_id_u.uid != IDMAP_SENTINEL_PID) {
3425 3425 if (req->id2name == NULL) {
3426 3426 /*
3427 3427 * If the lookup fails, go ahead anyway.
3428 3428 * The general UNIX rule is that it's OK to
3429 3429 * have a UID or GID that isn't in the
3430 3430 * name service.
3431 3431 */
3432 3432 retcode2 = ns_lookup_bypid(res->id.idmap_id_u.uid,
3433 3433 res->id.idtype == IDMAP_UID, &req->id2name);
3434 3434 if (IDMAP_ERROR(retcode2)) {
3435 3435 TRACE(req, res,
3436 3436 "Getting UNIX name, error=%d (ignored)",
3437 3437 retcode2);
3438 3438 } else {
3439 3439 TRACE(req, res, "Found UNIX name");
3440 3440 }
3441 3441 }
3442 3442 goto out;
3443 3443 }
3444 3444
3445 3445 /*
3446 3446 * If directory-based name mapping is enabled then the unixname
3447 3447 * may already have been retrieved from the AD object (AD-mode or
3448 3448 * mixed-mode) or from native LDAP object (nldap-mode) -- done.
3449 3449 */
3450 3450 if (req->id2name != NULL) {
3451 3451 assert(res->id.idtype != IDMAP_POSIXID);
3452 3452 if (AD_MODE(res->id.idtype, state))
3453 3453 res->direction = IDMAP_DIRECTION_BI;
3454 3454 else if (NLDAP_MODE(res->id.idtype, state))
3455 3455 res->direction = IDMAP_DIRECTION_BI;
3456 3456 else if (MIXED_MODE(res->id.idtype, state))
3457 3457 res->direction = IDMAP_DIRECTION_W2U;
3458 3458
3459 3459 /*
3460 3460 * Special case: (1) If the ad_unixuser_attr and
3461 3461 * ad_unixgroup_attr uses the same attribute
3462 3462 * name and (2) if this is a diagonal mapping
3463 3463 * request and (3) the unixname has been retrieved
3464 3464 * from the AD object -- then we ignore it and fallback
3465 3465 * to name-based mapping rules and ephemeral mapping
3466 3466 *
3467 3467 * Example:
3468 3468 * Properties:
3469 3469 * config/ad_unixuser_attr = "unixname"
3470 3470 * config/ad_unixgroup_attr = "unixname"
3471 3471 * AD user object:
3472 3472 * dn: cn=bob ...
3473 3473 * objectclass: user
3474 3474 * sam: bob
3475 3475 * unixname: bob1234
3476 3476 * AD group object:
3477 3477 * dn: cn=winadmins ...
3478 3478 * objectclass: group
3479 3479 * sam: winadmins
3480 3480 * unixname: unixadmins
3481 3481 *
3482 3482 * In this example whether "unixname" refers to a unixuser
3483 3483 * or unixgroup depends upon the AD object.
3484 3484 *
3485 3485 * $idmap show -c winname:bob gid
3486 3486 * AD lookup by "samAccountName=bob" for
3487 3487 * "ad_unixgroup_attr (i.e unixname)" for directory-based
3488 3488 * mapping would get "bob1234" which is not what we want.
3489 3489 * Now why not getgrnam_r("bob1234") and use it if it
3490 3490 * is indeed a unixgroup? That's because Unix can have
3491 3491 * users and groups with the same name and we clearly
3492 3492 * don't know the intention of the admin here.
3493 3493 * Therefore we ignore this and fallback to name-based
3494 3494 * mapping rules or ephemeral mapping.
3495 3495 */
3496 3496 if ((AD_MODE(res->id.idtype, state) ||
3497 3497 MIXED_MODE(res->id.idtype, state)) &&
3498 3498 state->ad_unixuser_attr != NULL &&
3499 3499 state->ad_unixgroup_attr != NULL &&
3500 3500 strcasecmp(state->ad_unixuser_attr,
3501 3501 state->ad_unixgroup_attr) == 0 &&
3502 3502 ((req->id1.idtype == IDMAP_USID &&
3503 3503 res->id.idtype == IDMAP_GID) ||
3504 3504 (req->id1.idtype == IDMAP_GSID &&
3505 3505 res->id.idtype == IDMAP_UID))) {
3506 3506 TRACE(req, res, "Ignoring UNIX name found in AD");
3507 3507 free(req->id2name);
3508 3508 req->id2name = NULL;
3509 3509 res->id.idmap_id_u.uid = IDMAP_SENTINEL_PID;
3510 3510 /* fallback */
3511 3511 } else {
3512 3512 if (res->id.idmap_id_u.uid == IDMAP_SENTINEL_PID) {
3513 3513 retcode = ns_lookup_byname(req->id2name,
3514 3514 NULL, &res->id);
3515 3515 if (retcode != IDMAP_SUCCESS) {
3516 3516 /*
3517 3517 * If ns_lookup_byname() fails that
3518 3518 * means the unixname (req->id2name),
3519 3519 * which was obtained from the AD
3520 3520 * object by directory-based mapping,
3521 3521 * is not a valid Unix user/group and
3522 3522 * therefore we return the error to the
3523 3523 * client instead of doing rule-based
3524 3524 * mapping or ephemeral mapping. This
3525 3525 * way the client can detect the issue.
3526 3526 */
3527 3527 TRACE(req, res,
3528 3528 "UNIX lookup error=%d", retcode);
3529 3529 goto out;
3530 3530 }
3531 3531 TRACE(req, res, "UNIX lookup");
3532 3532 }
3533 3533 goto out;
3534 3534 }
3535 3535 }
3536 3536
3537 3537 /* Free any mapping info from Directory based mapping */
3538 3538 if (res->info.how.map_type != IDMAP_MAP_TYPE_UNKNOWN)
3539 3539 idmap_how_clear(&res->info.how);
3540 3540
3541 3541 /*
3542 3542 * If we don't have unixname then evaluate local name-based
3543 3543 * mapping rules.
3544 3544 */
3545 3545 retcode = name_based_mapping_sid2pid(state, req, res);
3546 3546 if (retcode == IDMAP_SUCCESS) {
3547 3547 TRACE(req, res, "Rule-based mapping");
3548 3548 goto out;
3549 3549 } else if (retcode != IDMAP_ERR_NOTFOUND) {
3550 3550 TRACE(req, res, "Rule-based mapping error=%d", retcode);
3551 3551 goto out;
3552 3552 }
3553 3553
3554 3554 do_eph:
3555 3555 /* If not found, do ephemeral mapping */
3556 3556 retcode = dynamic_ephemeral_mapping(state, req, res);
3557 3557 if (retcode == IDMAP_SUCCESS) {
3558 3558 TRACE(req, res, "Ephemeral mapping");
3559 3559 goto out;
3560 3560 } else if (retcode != IDMAP_ERR_NOTFOUND) {
3561 3561 TRACE(req, res, "Ephemeral mapping error=%d", retcode);
3562 3562 goto out;
3563 3563 }
3564 3564
3565 3565 out:
3566 3566 res->retcode = idmap_stat4prot(retcode);
3567 3567 if (res->retcode != IDMAP_SUCCESS) {
3568 3568 req->direction = _IDMAP_F_DONE;
3569 3569 res->id.idmap_id_u.uid = UID_NOBODY;
3570 3570 }
3571 3571 if (!ARE_WE_DONE(req->direction))
3572 3572 state->sid2pid_done = FALSE;
3573 3573 return (retcode);
3574 3574 }
3575 3575
3576 3576 idmap_retcode
3577 3577 update_cache_pid2sid(lookup_state_t *state,
3578 3578 idmap_mapping *req, idmap_id_res *res)
3579 3579 {
3580 3580 char *sql = NULL;
3581 3581 idmap_retcode retcode;
3582 3582 idmap_retcode retcode2;
3583 3583 char *map_dn = NULL;
3584 3584 char *map_attr = NULL;
3585 3585 char *map_value = NULL;
3586 3586 char *map_windomain = NULL;
3587 3587 char *map_winname = NULL;
3588 3588 char *map_unixname = NULL;
3589 3589 int map_is_nt4 = FALSE;
3590 3590
3591 3591 /* Check if we need to cache anything */
3592 3592 if (ARE_WE_DONE(req->direction))
3593 3593 return (IDMAP_SUCCESS);
3594 3594
3595 3595 /* We don't cache negative entries */
3596 3596 if (res->retcode != IDMAP_SUCCESS)
3597 3597 return (IDMAP_SUCCESS);
3598 3598
3599 3599 assert(res->direction != IDMAP_DIRECTION_UNDEF);
3600 3600 assert(req->id1.idmap_id_u.uid != IDMAP_SENTINEL_PID);
3601 3601 assert(res->id.idtype != IDMAP_SID);
3602 3602
3603 3603 /*
3604 3604 * If we've gotten to this point and we *still* don't know the
3605 3605 * unixname, well, we'd like to have it now for the cache.
3606 3606 *
3607 3607 * If we truly always need it for the cache, we should probably
3608 3608 * look it up once at the beginning, rather than "at need" in
3609 3609 * several places as is now done. However, it's not really clear
3610 3610 * that we *do* need it in the cache; there's a decent argument
3611 3611 * that the cache should contain only SIDs and PIDs, so we'll
3612 3612 * leave our options open by doing it "at need" here too.
3613 3613 *
3614 3614 * If we can't find it... c'est la vie.
3615 3615 */
3616 3616 if (req->id1name == NULL) {
3617 3617 retcode2 = ns_lookup_bypid(req->id1.idmap_id_u.uid,
3618 3618 req->id1.idtype == IDMAP_UID, &req->id1name);
3619 3619 if (retcode2 == IDMAP_SUCCESS)
3620 3620 TRACE(req, res, "Found UNIX name");
3621 3621 else
3622 3622 TRACE(req, res, "Getting UNIX name error=%d", retcode2);
3623 3623 }
3624 3624
3625 3625 assert(res->info.how.map_type != IDMAP_MAP_TYPE_UNKNOWN);
3626 3626 switch (res->info.how.map_type) {
3627 3627 case IDMAP_MAP_TYPE_DS_AD:
3628 3628 map_dn = res->info.how.idmap_how_u.ad.dn;
3629 3629 map_attr = res->info.how.idmap_how_u.ad.attr;
3630 3630 map_value = res->info.how.idmap_how_u.ad.value;
3631 3631 break;
3632 3632
3633 3633 case IDMAP_MAP_TYPE_DS_NLDAP:
3634 3634 map_dn = res->info.how.idmap_how_u.nldap.dn;
3635 3635 map_attr = res->info.how.idmap_how_u.nldap.attr;
3636 3636 map_value = res->info.how.idmap_how_u.nldap.value;
3637 3637 break;
3638 3638
3639 3639 case IDMAP_MAP_TYPE_RULE_BASED:
3640 3640 map_windomain = res->info.how.idmap_how_u.rule.windomain;
3641 3641 map_winname = res->info.how.idmap_how_u.rule.winname;
3642 3642 map_unixname = res->info.how.idmap_how_u.rule.unixname;
3643 3643 map_is_nt4 = res->info.how.idmap_how_u.rule.is_nt4;
3644 3644 break;
3645 3645
3646 3646 case IDMAP_MAP_TYPE_EPHEMERAL:
3647 3647 break;
3648 3648
3649 3649 case IDMAP_MAP_TYPE_LOCAL_SID:
3650 3650 break;
3651 3651
3652 3652 case IDMAP_MAP_TYPE_IDMU:
3653 3653 map_dn = res->info.how.idmap_how_u.idmu.dn;
3654 3654 map_attr = res->info.how.idmap_how_u.idmu.attr;
3655 3655 map_value = res->info.how.idmap_how_u.idmu.value;
3656 3656 break;
3657 3657
3658 3658 default:
3659 3659 /* Don't cache other mapping types */
3660 3660 assert(FALSE);
3661 3661 }
3662 3662
3663 3663 /*
3664 3664 * Using NULL for u2w instead of 0 so that our trigger allows
3665 3665 * the same pid to be the destination in multiple entries
3666 3666 */
3667 3667 sql = sqlite_mprintf("INSERT OR REPLACE into idmap_cache "
3668 3668 "(sidprefix, rid, windomain, canon_winname, pid, unixname, "
3669 3669 "is_user, is_wuser, expiration, w2u, u2w, "
3670 3670 "map_type, map_dn, map_attr, map_value, map_windomain, "
3671 3671 "map_winname, map_unixname, map_is_nt4) "
3672 3672 "VALUES(%Q, %u, %Q, %Q, %u, %Q, %d, %d, "
3673 3673 "strftime('%%s','now') + %u, %q, 1, "
3674 3674 "%d, %Q, %Q, %Q, %Q, %Q, %Q, %d); ",
3675 3675 res->id.idmap_id_u.sid.prefix, res->id.idmap_id_u.sid.rid,
3676 3676 req->id2domain, req->id2name, req->id1.idmap_id_u.uid,
3677 3677 req->id1name, (req->id1.idtype == IDMAP_UID) ? 1 : 0,
3678 3678 (res->id.idtype == IDMAP_USID) ? 1 : 0,
3679 3679 state->id_cache_timeout,
3680 3680 (res->direction == 0) ? "1" : NULL,
3681 3681 res->info.how.map_type, map_dn, map_attr, map_value,
3682 3682 map_windomain, map_winname, map_unixname, map_is_nt4);
3683 3683
3684 3684 if (sql == NULL) {
3685 3685 retcode = IDMAP_ERR_INTERNAL;
3686 3686 idmapdlog(LOG_ERR, "Out of memory");
3687 3687 goto out;
3688 3688 }
3689 3689
3690 3690 retcode = sql_exec_no_cb(state->cache, IDMAP_CACHENAME, sql);
3691 3691 if (retcode != IDMAP_SUCCESS)
3692 3692 goto out;
3693 3693
3694 3694 state->pid2sid_done = FALSE;
3695 3695 sqlite_freemem(sql);
3696 3696 sql = NULL;
3697 3697
3698 3698 /* Check if we need to update namecache */
3699 3699 if (req->direction & _IDMAP_F_DONT_UPDATE_NAMECACHE)
3700 3700 goto out;
3701 3701
3702 3702 if (req->id2name == NULL)
3703 3703 goto out;
3704 3704
3705 3705 sql = sqlite_mprintf("INSERT OR REPLACE into name_cache "
3706 3706 "(sidprefix, rid, canon_name, domain, type, expiration) "
3707 3707 "VALUES(%Q, %u, %Q, %Q, %d, strftime('%%s','now') + %u); ",
3708 3708 res->id.idmap_id_u.sid.prefix, res->id.idmap_id_u.sid.rid,
3709 3709 req->id2name, req->id2domain,
3710 3710 res->id.idtype, state->name_cache_timeout);
3711 3711
3712 3712 if (sql == NULL) {
3713 3713 retcode = IDMAP_ERR_INTERNAL;
3714 3714 idmapdlog(LOG_ERR, "Out of memory");
3715 3715 goto out;
3716 3716 }
3717 3717
3718 3718 retcode = sql_exec_no_cb(state->cache, IDMAP_CACHENAME, sql);
3719 3719
3720 3720 out:
3721 3721 if (sql != NULL)
3722 3722 sqlite_freemem(sql);
3723 3723 return (retcode);
3724 3724 }
3725 3725
3726 3726 idmap_retcode
3727 3727 update_cache_sid2pid(lookup_state_t *state,
3728 3728 idmap_mapping *req, idmap_id_res *res)
3729 3729 {
3730 3730 char *sql = NULL;
3731 3731 idmap_retcode retcode;
3732 3732 int is_eph_user;
3733 3733 char *map_dn = NULL;
3734 3734 char *map_attr = NULL;
3735 3735 char *map_value = NULL;
3736 3736 char *map_windomain = NULL;
3737 3737 char *map_winname = NULL;
3738 3738 char *map_unixname = NULL;
3739 3739 int map_is_nt4 = FALSE;
3740 3740
3741 3741 /* Check if we need to cache anything */
3742 3742 if (ARE_WE_DONE(req->direction))
3743 3743 return (IDMAP_SUCCESS);
3744 3744
3745 3745 /* We don't cache negative entries */
3746 3746 if (res->retcode != IDMAP_SUCCESS)
3747 3747 return (IDMAP_SUCCESS);
3748 3748
3749 3749 if (req->direction & _IDMAP_F_EXP_EPH_UID)
3750 3750 is_eph_user = 1;
3751 3751 else if (req->direction & _IDMAP_F_EXP_EPH_GID)
3752 3752 is_eph_user = 0;
3753 3753 else
3754 3754 is_eph_user = -1;
3755 3755
3756 3756 if (is_eph_user >= 0 &&
3757 3757 !IDMAP_ID_IS_EPHEMERAL(res->id.idmap_id_u.uid)) {
3758 3758 sql = sqlite_mprintf("UPDATE idmap_cache "
3759 3759 "SET w2u = 0 WHERE "
3760 3760 "sidprefix = %Q AND rid = %u AND w2u = 1 AND "
3761 3761 "pid >= 2147483648 AND is_user = %d;",
3762 3762 req->id1.idmap_id_u.sid.prefix,
3763 3763 req->id1.idmap_id_u.sid.rid,
3764 3764 is_eph_user);
3765 3765 if (sql == NULL) {
3766 3766 retcode = IDMAP_ERR_INTERNAL;
3767 3767 idmapdlog(LOG_ERR, "Out of memory");
3768 3768 goto out;
3769 3769 }
3770 3770
3771 3771 retcode = sql_exec_no_cb(state->cache, IDMAP_CACHENAME, sql);
3772 3772 if (retcode != IDMAP_SUCCESS)
3773 3773 goto out;
3774 3774
3775 3775 sqlite_freemem(sql);
3776 3776 sql = NULL;
3777 3777 }
3778 3778
3779 3779 assert(res->direction != IDMAP_DIRECTION_UNDEF);
3780 3780 assert(res->id.idmap_id_u.uid != IDMAP_SENTINEL_PID);
3781 3781
3782 3782 switch (res->info.how.map_type) {
3783 3783 case IDMAP_MAP_TYPE_DS_AD:
3784 3784 map_dn = res->info.how.idmap_how_u.ad.dn;
3785 3785 map_attr = res->info.how.idmap_how_u.ad.attr;
3786 3786 map_value = res->info.how.idmap_how_u.ad.value;
3787 3787 break;
3788 3788
3789 3789 case IDMAP_MAP_TYPE_DS_NLDAP:
3790 3790 map_dn = res->info.how.idmap_how_u.nldap.dn;
3791 3791 map_attr = res->info.how.idmap_how_u.ad.attr;
3792 3792 map_value = res->info.how.idmap_how_u.nldap.value;
3793 3793 break;
3794 3794
3795 3795 case IDMAP_MAP_TYPE_RULE_BASED:
3796 3796 map_windomain = res->info.how.idmap_how_u.rule.windomain;
3797 3797 map_winname = res->info.how.idmap_how_u.rule.winname;
3798 3798 map_unixname = res->info.how.idmap_how_u.rule.unixname;
3799 3799 map_is_nt4 = res->info.how.idmap_how_u.rule.is_nt4;
3800 3800 break;
3801 3801
3802 3802 case IDMAP_MAP_TYPE_EPHEMERAL:
3803 3803 break;
3804 3804
3805 3805 case IDMAP_MAP_TYPE_IDMU:
3806 3806 map_dn = res->info.how.idmap_how_u.idmu.dn;
3807 3807 map_attr = res->info.how.idmap_how_u.idmu.attr;
3808 3808 map_value = res->info.how.idmap_how_u.idmu.value;
3809 3809 break;
3810 3810
3811 3811 default:
3812 3812 /* Don't cache other mapping types */
3813 3813 assert(FALSE);
3814 3814 }
3815 3815
3816 3816 sql = sqlite_mprintf("INSERT OR REPLACE into idmap_cache "
3817 3817 "(sidprefix, rid, windomain, canon_winname, pid, unixname, "
3818 3818 "is_user, is_wuser, expiration, w2u, u2w, "
3819 3819 "map_type, map_dn, map_attr, map_value, map_windomain, "
3820 3820 "map_winname, map_unixname, map_is_nt4) "
3821 3821 "VALUES(%Q, %u, %Q, %Q, %u, %Q, %d, %d, "
3822 3822 "strftime('%%s','now') + %u, 1, %q, "
3823 3823 "%d, %Q, %Q, %Q, %Q, %Q, %Q, %d);",
3824 3824 req->id1.idmap_id_u.sid.prefix, req->id1.idmap_id_u.sid.rid,
3825 3825 (req->id1domain != NULL) ? req->id1domain : "", req->id1name,
3826 3826 res->id.idmap_id_u.uid, req->id2name,
3827 3827 (res->id.idtype == IDMAP_UID) ? 1 : 0,
3828 3828 (req->id1.idtype == IDMAP_USID) ? 1 : 0,
3829 3829 state->id_cache_timeout,
3830 3830 (res->direction == 0) ? "1" : NULL,
3831 3831 res->info.how.map_type, map_dn, map_attr, map_value,
3832 3832 map_windomain, map_winname, map_unixname, map_is_nt4);
3833 3833
3834 3834 if (sql == NULL) {
3835 3835 retcode = IDMAP_ERR_INTERNAL;
3836 3836 idmapdlog(LOG_ERR, "Out of memory");
3837 3837 goto out;
3838 3838 }
3839 3839
3840 3840 retcode = sql_exec_no_cb(state->cache, IDMAP_CACHENAME, sql);
3841 3841 if (retcode != IDMAP_SUCCESS)
3842 3842 goto out;
3843 3843
3844 3844 state->sid2pid_done = FALSE;
3845 3845 sqlite_freemem(sql);
3846 3846 sql = NULL;
3847 3847
3848 3848 /* Check if we need to update namecache */
3849 3849 if (req->direction & _IDMAP_F_DONT_UPDATE_NAMECACHE)
3850 3850 goto out;
3851 3851
3852 3852 if (EMPTY_STRING(req->id1name))
3853 3853 goto out;
3854 3854
3855 3855 sql = sqlite_mprintf("INSERT OR REPLACE into name_cache "
3856 3856 "(sidprefix, rid, canon_name, domain, type, expiration) "
3857 3857 "VALUES(%Q, %u, %Q, %Q, %d, strftime('%%s','now') + %u); ",
3858 3858 req->id1.idmap_id_u.sid.prefix, req->id1.idmap_id_u.sid.rid,
3859 3859 req->id1name, req->id1domain,
3860 3860 req->id1.idtype, state->name_cache_timeout);
3861 3861
3862 3862 if (sql == NULL) {
3863 3863 retcode = IDMAP_ERR_INTERNAL;
3864 3864 idmapdlog(LOG_ERR, "Out of memory");
3865 3865 goto out;
3866 3866 }
3867 3867
3868 3868 retcode = sql_exec_no_cb(state->cache, IDMAP_CACHENAME, sql);
3869 3869
3870 3870 out:
3871 3871 if (sql != NULL)
3872 3872 sqlite_freemem(sql);
3873 3873 return (retcode);
3874 3874 }
3875 3875
3876 3876 static
3877 3877 idmap_retcode
3878 3878 lookup_cache_pid2sid(sqlite *cache, idmap_mapping *req, idmap_id_res *res,
3879 3879 int is_user)
3880 3880 {
3881 3881 char *end;
3882 3882 char *sql = NULL;
3883 3883 const char **values;
3884 3884 sqlite_vm *vm = NULL;
3885 3885 int ncol;
3886 3886 idmap_retcode retcode = IDMAP_SUCCESS;
3887 3887 time_t curtime;
3888 3888 idmap_id_type idtype;
3889 3889
3890 3890 /* Current time */
3891 3891 errno = 0;
3892 3892 if ((curtime = time(NULL)) == (time_t)-1) {
3893 3893 idmapdlog(LOG_ERR, "Failed to get current time (%s)",
3894 3894 strerror(errno));
3895 3895 retcode = IDMAP_ERR_INTERNAL;
3896 3896 goto out;
3897 3897 }
3898 3898
3899 3899 /* SQL to lookup the cache by pid or by unixname */
3900 3900 if (req->id1.idmap_id_u.uid != IDMAP_SENTINEL_PID) {
3901 3901 sql = sqlite_mprintf("SELECT sidprefix, rid, "
3902 3902 "canon_winname, windomain, w2u, is_wuser, "
3903 3903 "map_type, map_dn, map_attr, map_value, map_windomain, "
3904 3904 "map_winname, map_unixname, map_is_nt4 "
3905 3905 "FROM idmap_cache WHERE "
3906 3906 "pid = %u AND u2w = 1 AND is_user = %d AND "
3907 3907 "(pid >= 2147483648 OR "
3908 3908 "(expiration = 0 OR expiration ISNULL OR "
3909 3909 "expiration > %d));",
3910 3910 req->id1.idmap_id_u.uid, is_user, curtime);
3911 3911 } else if (req->id1name != NULL) {
3912 3912 sql = sqlite_mprintf("SELECT sidprefix, rid, "
3913 3913 "canon_winname, windomain, w2u, is_wuser, "
3914 3914 "map_type, map_dn, map_attr, map_value, map_windomain, "
3915 3915 "map_winname, map_unixname, map_is_nt4 "
3916 3916 "FROM idmap_cache WHERE "
3917 3917 "unixname = %Q AND u2w = 1 AND is_user = %d AND "
3918 3918 "(pid >= 2147483648 OR "
3919 3919 "(expiration = 0 OR expiration ISNULL OR "
3920 3920 "expiration > %d));",
3921 3921 req->id1name, is_user, curtime);
3922 3922 } else {
3923 3923 retcode = IDMAP_ERR_ARG;
3924 3924 goto out;
3925 3925 }
3926 3926
3927 3927 if (sql == NULL) {
3928 3928 idmapdlog(LOG_ERR, "Out of memory");
3929 3929 retcode = IDMAP_ERR_MEMORY;
3930 3930 goto out;
3931 3931 }
3932 3932 retcode = sql_compile_n_step_once(
3933 3933 cache, sql, &vm, &ncol, 14, &values);
3934 3934 sqlite_freemem(sql);
3935 3935
3936 3936 if (retcode == IDMAP_ERR_NOTFOUND)
3937 3937 goto out;
3938 3938 else if (retcode == IDMAP_SUCCESS) {
3939 3939 /* sanity checks */
3940 3940 if (values[0] == NULL || values[1] == NULL) {
3941 3941 retcode = IDMAP_ERR_CACHE;
3942 3942 goto out;
3943 3943 }
3944 3944
3945 3945 switch (res->id.idtype) {
3946 3946 case IDMAP_SID:
3947 3947 case IDMAP_USID:
3948 3948 case IDMAP_GSID:
3949 3949 idtype = strtol(values[5], &end, 10) == 1
3950 3950 ? IDMAP_USID : IDMAP_GSID;
3951 3951
3952 3952 if (res->id.idtype == IDMAP_USID &&
3953 3953 idtype != IDMAP_USID) {
3954 3954 retcode = IDMAP_ERR_NOTUSER;
3955 3955 goto out;
3956 3956 } else if (res->id.idtype == IDMAP_GSID &&
3957 3957 idtype != IDMAP_GSID) {
3958 3958 retcode = IDMAP_ERR_NOTGROUP;
3959 3959 goto out;
3960 3960 }
3961 3961 res->id.idtype = idtype;
3962 3962
3963 3963 res->id.idmap_id_u.sid.rid =
3964 3964 strtoul(values[1], &end, 10);
3965 3965 res->id.idmap_id_u.sid.prefix = strdup(values[0]);
3966 3966 if (res->id.idmap_id_u.sid.prefix == NULL) {
3967 3967 idmapdlog(LOG_ERR, "Out of memory");
3968 3968 retcode = IDMAP_ERR_MEMORY;
3969 3969 goto out;
3970 3970 }
3971 3971
3972 3972 if (values[4] != NULL)
3973 3973 res->direction =
3974 3974 (strtol(values[4], &end, 10) == 0)?
3975 3975 IDMAP_DIRECTION_U2W:IDMAP_DIRECTION_BI;
3976 3976 else
3977 3977 res->direction = IDMAP_DIRECTION_U2W;
3978 3978
3979 3979 if (values[2] == NULL)
3980 3980 break;
3981 3981 req->id2name = strdup(values[2]);
3982 3982 if (req->id2name == NULL) {
3983 3983 idmapdlog(LOG_ERR, "Out of memory");
3984 3984 retcode = IDMAP_ERR_MEMORY;
3985 3985 goto out;
3986 3986 }
3987 3987
3988 3988 if (values[3] == NULL)
3989 3989 break;
3990 3990 req->id2domain = strdup(values[3]);
3991 3991 if (req->id2domain == NULL) {
3992 3992 idmapdlog(LOG_ERR, "Out of memory");
3993 3993 retcode = IDMAP_ERR_MEMORY;
3994 3994 goto out;
3995 3995 }
3996 3996
3997 3997 break;
3998 3998 default:
3999 3999 retcode = IDMAP_ERR_NOTSUPPORTED;
4000 4000 break;
4001 4001 }
4002 4002 if (req->flag & IDMAP_REQ_FLG_MAPPING_INFO) {
4003 4003 res->info.src = IDMAP_MAP_SRC_CACHE;
4004 4004 res->info.how.map_type = strtoul(values[6], &end, 10);
4005 4005 switch (res->info.how.map_type) {
4006 4006 case IDMAP_MAP_TYPE_DS_AD:
4007 4007 res->info.how.idmap_how_u.ad.dn =
4008 4008 strdup(values[7]);
4009 4009 res->info.how.idmap_how_u.ad.attr =
4010 4010 strdup(values[8]);
4011 4011 res->info.how.idmap_how_u.ad.value =
4012 4012 strdup(values[9]);
4013 4013 break;
4014 4014
4015 4015 case IDMAP_MAP_TYPE_DS_NLDAP:
4016 4016 res->info.how.idmap_how_u.nldap.dn =
4017 4017 strdup(values[7]);
4018 4018 res->info.how.idmap_how_u.nldap.attr =
4019 4019 strdup(values[8]);
4020 4020 res->info.how.idmap_how_u.nldap.value =
4021 4021 strdup(values[9]);
4022 4022 break;
4023 4023
4024 4024 case IDMAP_MAP_TYPE_RULE_BASED:
4025 4025 res->info.how.idmap_how_u.rule.windomain =
4026 4026 strdup(values[10]);
4027 4027 res->info.how.idmap_how_u.rule.winname =
4028 4028 strdup(values[11]);
4029 4029 res->info.how.idmap_how_u.rule.unixname =
4030 4030 strdup(values[12]);
4031 4031 res->info.how.idmap_how_u.rule.is_nt4 =
4032 4032 strtoul(values[13], &end, 10);
4033 4033 res->info.how.idmap_how_u.rule.is_user =
4034 4034 is_user;
4035 4035 res->info.how.idmap_how_u.rule.is_wuser =
4036 4036 strtol(values[5], &end, 10);
4037 4037 break;
4038 4038
4039 4039 case IDMAP_MAP_TYPE_EPHEMERAL:
4040 4040 break;
4041 4041
4042 4042 case IDMAP_MAP_TYPE_LOCAL_SID:
4043 4043 break;
4044 4044
4045 4045 case IDMAP_MAP_TYPE_KNOWN_SID:
4046 4046 break;
4047 4047
4048 4048 case IDMAP_MAP_TYPE_IDMU:
4049 4049 res->info.how.idmap_how_u.idmu.dn =
4050 4050 strdup(values[7]);
4051 4051 res->info.how.idmap_how_u.idmu.attr =
4052 4052 strdup(values[8]);
4053 4053 res->info.how.idmap_how_u.idmu.value =
4054 4054 strdup(values[9]);
4055 4055 break;
4056 4056
4057 4057 default:
4058 4058 /* Unknown mapping type */
4059 4059 assert(FALSE);
4060 4060 }
4061 4061 }
4062 4062 }
4063 4063
4064 4064 out:
4065 4065 if (vm != NULL)
4066 4066 (void) sqlite_finalize(vm, NULL);
4067 4067 return (retcode);
4068 4068 }
4069 4069
4070 4070 /*
4071 4071 * Given:
4072 4072 * cache sqlite handle
4073 4073 * name Windows user name
4074 4074 * domain Windows domain name
4075 4075 *
4076 4076 * Return: Error code
4077 4077 *
4078 4078 * *canonname Canonical name (if canonname is non-NULL) [1]
4079 4079 * *sidprefix SID prefix [1]
4080 4080 * *rid RID
4081 4081 * *type Type of name
4082 4082 *
4083 4083 * [1] malloc'ed, NULL on error
4084 4084 */
4085 4085 static
4086 4086 idmap_retcode
4087 4087 lookup_cache_name2sid(
4088 4088 sqlite *cache,
4089 4089 const char *name,
4090 4090 const char *domain,
4091 4091 char **canonname,
4092 4092 char **sidprefix,
4093 4093 idmap_rid_t *rid,
4094 4094 idmap_id_type *type)
4095 4095 {
4096 4096 char *end, *lower_name;
4097 4097 char *sql;
4098 4098 const char **values;
4099 4099 sqlite_vm *vm = NULL;
4100 4100 int ncol;
4101 4101 time_t curtime;
4102 4102 idmap_retcode retcode;
4103 4103
4104 4104 *sidprefix = NULL;
4105 4105 if (canonname != NULL)
4106 4106 *canonname = NULL;
4107 4107
4108 4108 /* Get current time */
4109 4109 errno = 0;
4110 4110 if ((curtime = time(NULL)) == (time_t)-1) {
4111 4111 idmapdlog(LOG_ERR, "Failed to get current time (%s)",
4112 4112 strerror(errno));
4113 4113 retcode = IDMAP_ERR_INTERNAL;
4114 4114 goto out;
4115 4115 }
4116 4116
4117 4117 /* SQL to lookup the cache */
4118 4118 if ((lower_name = tolower_u8(name)) == NULL)
4119 4119 lower_name = (char *)name;
4120 4120 sql = sqlite_mprintf("SELECT sidprefix, rid, type, canon_name "
4121 4121 "FROM name_cache WHERE name = %Q AND domain = %Q AND "
4122 4122 "(expiration = 0 OR expiration ISNULL OR "
4123 4123 "expiration > %d);", lower_name, domain, curtime);
4124 4124 if (lower_name != name)
4125 4125 free(lower_name);
4126 4126 if (sql == NULL) {
4127 4127 idmapdlog(LOG_ERR, "Out of memory");
4128 4128 retcode = IDMAP_ERR_MEMORY;
4129 4129 goto out;
4130 4130 }
4131 4131 retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 4, &values);
4132 4132
4133 4133 sqlite_freemem(sql);
4134 4134
4135 4135 if (retcode != IDMAP_SUCCESS)
4136 4136 goto out;
4137 4137
4138 4138 if (type != NULL) {
4139 4139 if (values[2] == NULL) {
4140 4140 retcode = IDMAP_ERR_CACHE;
4141 4141 goto out;
4142 4142 }
4143 4143 *type = xlate_legacy_type(strtol(values[2], &end, 10));
4144 4144 }
4145 4145
4146 4146 if (values[0] == NULL || values[1] == NULL) {
4147 4147 retcode = IDMAP_ERR_CACHE;
4148 4148 goto out;
4149 4149 }
4150 4150
4151 4151 if (canonname != NULL) {
4152 4152 assert(values[3] != NULL);
4153 4153 *canonname = strdup(values[3]);
4154 4154 if (*canonname == NULL) {
4155 4155 idmapdlog(LOG_ERR, "Out of memory");
4156 4156 retcode = IDMAP_ERR_MEMORY;
4157 4157 goto out;
4158 4158 }
4159 4159 }
4160 4160
4161 4161 *sidprefix = strdup(values[0]);
4162 4162 if (*sidprefix == NULL) {
4163 4163 idmapdlog(LOG_ERR, "Out of memory");
4164 4164 retcode = IDMAP_ERR_MEMORY;
4165 4165 goto out;
4166 4166 }
4167 4167 *rid = strtoul(values[1], &end, 10);
4168 4168
4169 4169 retcode = IDMAP_SUCCESS;
4170 4170
4171 4171 out:
4172 4172 if (vm != NULL)
4173 4173 (void) sqlite_finalize(vm, NULL);
4174 4174
4175 4175 if (retcode != IDMAP_SUCCESS) {
4176 4176 free(*sidprefix);
4177 4177 *sidprefix = NULL;
4178 4178 if (canonname != NULL) {
4179 4179 free(*canonname);
4180 4180 *canonname = NULL;
4181 4181 }
4182 4182 }
4183 4183 return (retcode);
4184 4184 }
4185 4185
4186 4186 static
4187 4187 idmap_retcode
4188 4188 ad_lookup_by_winname(lookup_state_t *state,
4189 4189 const char *name, const char *domain, int esidtype,
4190 4190 char **dn, char **attr, char **value, char **canonname,
4191 4191 char **sidprefix, idmap_rid_t *rid, idmap_id_type *wintype,
4192 4192 char **unixname)
4193 4193 {
4194 4194 int retries;
4195 4195 idmap_query_state_t *qs = NULL;
4196 4196 idmap_retcode rc, retcode;
4197 4197 int i;
4198 4198 int found_ad = 0;
4199 4199
4200 4200 RDLOCK_CONFIG();
4201 4201 if (_idmapdstate.num_gcs > 0) {
4202 4202 for (i = 0; i < _idmapdstate.num_gcs && !found_ad; i++) {
4203 4203 retries = 0;
4204 4204 retry:
4205 4205 retcode = idmap_lookup_batch_start(
4206 4206 _idmapdstate.gcs[i],
4207 4207 1,
4208 4208 _idmapdstate.cfg->pgcfg.directory_based_mapping,
4209 4209 _idmapdstate.cfg->pgcfg.default_domain,
4210 4210 &qs);
4211 4211 if (retcode != IDMAP_SUCCESS) {
4212 4212 if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR &&
4213 4213 retries++ < ADUTILS_DEF_NUM_RETRIES)
4214 4214 goto retry;
4215 4215 degrade_svc(1, "failed to create request for "
4216 4216 "AD lookup by winname");
4217 4217 return (retcode);
4218 4218 }
4219 4219
4220 4220 restore_svc();
4221 4221
4222 4222 if (state != NULL && i == 0) {
4223 4223 /*
4224 4224 * Directory based name mapping is only
4225 4225 * performed within the joined forest (i == 0).
4226 4226 * We don't trust other "trusted" forests to
4227 4227 * provide DS-based name mapping information
4228 4228 * because AD's definition of "cross-forest
4229 4229 * trust" does not encompass this sort of
4230 4230 * behavior.
4231 4231 */
4232 4232 idmap_lookup_batch_set_unixattr(qs,
4233 4233 state->ad_unixuser_attr,
4234 4234 state->ad_unixgroup_attr);
4235 4235 }
4236 4236
4237 4237 retcode = idmap_name2sid_batch_add1(qs, name, domain,
4238 4238 esidtype, dn, attr, value, canonname, sidprefix,
4239 4239 rid, wintype, unixname, NULL, &rc);
4240 4240 if (retcode == IDMAP_ERR_DOMAIN_NOTFOUND) {
4241 4241 idmap_lookup_release_batch(&qs);
4242 4242 continue;
4243 4243 }
4244 4244 found_ad = 1;
4245 4245 if (retcode != IDMAP_SUCCESS)
4246 4246 idmap_lookup_release_batch(&qs);
4247 4247 else
4248 4248 retcode = idmap_lookup_batch_end(&qs);
4249 4249
4250 4250 if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR &&
4251 4251 retries++ < ADUTILS_DEF_NUM_RETRIES)
4252 4252 goto retry;
4253 4253 else if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR)
4254 4254 degrade_svc(1,
4255 4255 "some AD lookups timed out repeatedly");
4256 4256 }
4257 4257 } else {
4258 4258 /* No AD case */
4259 4259 retcode = IDMAP_ERR_NO_ACTIVEDIRECTORY;
4260 4260 }
4261 4261 UNLOCK_CONFIG();
4262 4262
4263 4263 if (retcode != IDMAP_SUCCESS) {
4264 4264 idmapdlog(LOG_NOTICE,
4265 4265 "AD lookup of winname %s@%s failed, error code %d",
4266 4266 name == NULL ? "(null)" : name,
4267 4267 domain == NULL ? "(null)" : domain,
4268 4268 retcode);
4269 4269 return (retcode);
4270 4270 }
4271 4271 return (rc);
4272 4272 }
4273 4273
4274 4274 /*
4275 4275 * Given:
4276 4276 * cache sqlite handle to cache
4277 4277 * name Windows user name
4278 4278 * domain Windows domain name
4279 4279 * local_only if true, don't try AD lookups
4280 4280 *
4281 4281 * Returns: Error code
4282 4282 *
4283 4283 * *canonname Canonical name (if non-NULL) [1]
4284 4284 * *canondomain Canonical domain (if non-NULL) [1]
4285 4285 * *sidprefix SID prefix [1]
4286 4286 * *rid RID
4287 4287 * *req Request (direction is updated)
4288 4288 *
4289 4289 * [1] malloc'ed, NULL on error
4290 4290 */
4291 4291 idmap_retcode
4292 4292 lookup_name2sid(
4293 4293 sqlite *cache,
4294 4294 const char *name,
4295 4295 const char *domain,
4296 4296 int want_wuser,
4297 4297 char **canonname,
4298 4298 char **canondomain,
4299 4299 char **sidprefix,
4300 4300 idmap_rid_t *rid,
4301 4301 idmap_id_type *type,
4302 4302 idmap_mapping *req,
4303 4303 int local_only)
4304 4304 {
4305 4305 idmap_retcode retcode;
4306 4306
4307 4307 *sidprefix = NULL;
4308 4308 if (canonname != NULL)
4309 4309 *canonname = NULL;
4310 4310 if (canondomain != NULL)
4311 4311 *canondomain = NULL;
4312 4312
4313 4313 /* Lookup well-known SIDs table */
4314 4314 retcode = lookup_wksids_name2sid(name, domain, canonname, canondomain,
4315 4315 sidprefix, rid, type);
4316 4316 if (retcode == IDMAP_SUCCESS) {
4317 4317 req->direction |= _IDMAP_F_DONT_UPDATE_NAMECACHE;
4318 4318 goto out;
4319 4319 } else if (retcode != IDMAP_ERR_NOTFOUND) {
4320 4320 return (retcode);
4321 4321 }
4322 4322
4323 4323 /* Lookup cache */
4324 4324 retcode = lookup_cache_name2sid(cache, name, domain, canonname,
4325 4325 sidprefix, rid, type);
4326 4326 if (retcode == IDMAP_SUCCESS) {
4327 4327 req->direction |= _IDMAP_F_DONT_UPDATE_NAMECACHE;
4328 4328 goto out;
4329 4329 } else if (retcode != IDMAP_ERR_NOTFOUND) {
4330 4330 return (retcode);
4331 4331 }
4332 4332
4333 4333 /*
4334 4334 * The caller may be using this function to determine if this
4335 4335 * request needs to be marked for AD lookup or not
4336 4336 * (i.e. _IDMAP_F_LOOKUP_AD) and therefore may not want this
4337 4337 * function to AD lookup now.
4338 4338 */
4339 4339 if (local_only)
4340 4340 return (retcode);
4341 4341
4342 4342 if (_idmapdstate.cfg->pgcfg.use_lsa &&
4343 4343 _idmapdstate.cfg->pgcfg.domain_name != NULL &&
4344 4344 name != NULL && *sidprefix == NULL) {
4345 4345 retcode = lookup_lsa_by_name(name, domain,
4346 4346 sidprefix, rid,
4347 4347 canonname, canondomain,
4348 4348 type);
4349 4349 if (retcode == IDMAP_SUCCESS)
4350 4350 goto out;
4351 4351 else if (retcode != IDMAP_ERR_NOTFOUND)
4352 4352 return (retcode);
4353 4353 }
4354 4354
4355 4355 /* Lookup AD */
4356 4356 retcode = ad_lookup_by_winname(NULL, name, domain, IDMAP_POSIXID,
4357 4357 NULL, NULL, NULL, canonname, sidprefix, rid, type, NULL);
4358 4358 if (retcode != IDMAP_SUCCESS)
4359 4359 return (retcode);
4360 4360
4361 4361 out:
4362 4362 /*
4363 4363 * Entry found (cache or Windows lookup)
4364 4364 */
4365 4365 if (want_wuser == 1 && *type != IDMAP_USID)
4366 4366 retcode = IDMAP_ERR_NOTUSER;
4367 4367 else if (want_wuser == 0 && *type != IDMAP_GSID)
4368 4368 retcode = IDMAP_ERR_NOTGROUP;
4369 4369 else if (want_wuser == -1) {
4370 4370 /*
4371 4371 * Caller wants to know if its user or group
4372 4372 * Verify that it's one or the other.
4373 4373 */
4374 4374 if (*type != IDMAP_USID && *type != IDMAP_GSID)
4375 4375 retcode = IDMAP_ERR_SID;
4376 4376 }
4377 4377
4378 4378 if (retcode == IDMAP_SUCCESS) {
4379 4379 /*
4380 4380 * If we were asked for a canonical domain and none
4381 4381 * of the searches have provided one, assume it's the
4382 4382 * supplied domain.
4383 4383 */
4384 4384 if (canondomain != NULL && *canondomain == NULL) {
4385 4385 *canondomain = strdup(domain);
4386 4386 if (*canondomain == NULL)
4387 4387 retcode = IDMAP_ERR_MEMORY;
4388 4388 }
4389 4389 }
4390 4390 if (retcode != IDMAP_SUCCESS) {
4391 4391 free(*sidprefix);
4392 4392 *sidprefix = NULL;
4393 4393 if (canonname != NULL) {
4394 4394 free(*canonname);
4395 4395 *canonname = NULL;
4396 4396 }
4397 4397 if (canondomain != NULL) {
4398 4398 free(*canondomain);
4399 4399 *canondomain = NULL;
4400 4400 }
4401 4401 }
4402 4402 return (retcode);
4403 4403 }
4404 4404
4405 4405 static
4406 4406 idmap_retcode
4407 4407 name_based_mapping_pid2sid(lookup_state_t *state, const char *unixname,
4408 4408 int is_user, idmap_mapping *req, idmap_id_res *res)
4409 4409 {
4410 4410 const char *winname, *windomain;
4411 4411 char *canonname;
4412 4412 char *canondomain;
4413 4413 char *sql = NULL, *errmsg = NULL;
4414 4414 idmap_retcode retcode;
4415 4415 char *end;
4416 4416 const char **values;
4417 4417 sqlite_vm *vm = NULL;
4418 4418 int ncol, r;
4419 4419 int want_wuser;
4420 4420 const char *me = "name_based_mapping_pid2sid";
4421 4421 idmap_namerule *rule = &res->info.how.idmap_how_u.rule;
4422 4422 int direction;
4423 4423
4424 4424 assert(unixname != NULL); /* We have unixname */
4425 4425 assert(req->id2name == NULL); /* We don't have winname */
4426 4426 assert(res->id.idmap_id_u.sid.prefix == NULL); /* No SID either */
4427 4427
4428 4428 sql = sqlite_mprintf(
4429 4429 "SELECT winname_display, windomain, w2u_order, "
4430 4430 "is_wuser, unixname, is_nt4 "
4431 4431 "FROM namerules WHERE "
4432 4432 "u2w_order > 0 AND is_user = %d AND "
4433 4433 "(unixname = %Q OR unixname = '*') "
4434 4434 "ORDER BY u2w_order ASC;", is_user, unixname);
4435 4435 if (sql == NULL) {
4436 4436 idmapdlog(LOG_ERR, "Out of memory");
4437 4437 retcode = IDMAP_ERR_MEMORY;
4438 4438 goto out;
4439 4439 }
4440 4440
4441 4441 if (sqlite_compile(state->db, sql, NULL, &vm, &errmsg) != SQLITE_OK) {
4442 4442 retcode = IDMAP_ERR_INTERNAL;
4443 4443 idmapdlog(LOG_ERR, "%s: database error (%s)", me,
4444 4444 CHECK_NULL(errmsg));
4445 4445 sqlite_freemem(errmsg);
4446 4446 goto out;
4447 4447 }
4448 4448
4449 4449 for (;;) {
4450 4450 r = sqlite_step(vm, &ncol, &values, NULL);
4451 4451 assert(r != SQLITE_LOCKED && r != SQLITE_BUSY);
4452 4452 if (r == SQLITE_ROW) {
4453 4453 if (ncol < 6) {
4454 4454 retcode = IDMAP_ERR_INTERNAL;
4455 4455 goto out;
4456 4456 }
4457 4457
4458 4458 TRACE(req, res, "Matching rule: %s -> %s@%s",
4459 4459 values[4] == NULL ? "(null)" : values[4],
4460 4460 values[0] == NULL ? "(null)" : values[0],
4461 4461 values[1] == NULL ? "(null)" : values[1]);
4462 4462
4463 4463 if (values[0] == NULL) {
4464 4464 /* values [1] and [2] can be null */
4465 4465 retcode = IDMAP_ERR_INTERNAL;
4466 4466 goto out;
4467 4467 }
4468 4468
4469 4469 if (values[2] != NULL)
4470 4470 direction =
4471 4471 (strtol(values[2], &end, 10) == 0)?
4472 4472 IDMAP_DIRECTION_U2W:IDMAP_DIRECTION_BI;
4473 4473 else
4474 4474 direction = IDMAP_DIRECTION_U2W;
4475 4475
4476 4476 if (EMPTY_NAME(values[0])) {
4477 4477 idmap_namerule_set(rule, values[1], values[0],
4478 4478 values[4], is_user,
4479 4479 strtol(values[3], &end, 10),
4480 4480 strtol(values[5], &end, 10),
4481 4481 direction);
4482 4482 TRACE(req, res, "Mapping inhibited");
4483 4483 retcode = IDMAP_ERR_NOMAPPING;
4484 4484 goto out;
4485 4485 }
4486 4486
4487 4487 if (values[0][0] == '*') {
4488 4488 winname = unixname;
4489 4489 } else {
4490 4490 winname = values[0];
4491 4491 }
4492 4492
4493 4493 want_wuser = res->id.idtype == IDMAP_USID ? 1
4494 4494 : res->id.idtype == IDMAP_GSID ? 0
4495 4495 : -1;
4496 4496 if (values[1] != NULL)
4497 4497 windomain = values[1];
4498 4498 else if (state->defdom != NULL) {
4499 4499 windomain = state->defdom;
4500 4500 TRACE(req, res,
4501 4501 "Added default domain %s to rule",
4502 4502 windomain);
4503 4503 } else {
4504 4504 idmapdlog(LOG_ERR, "%s: no domain", me);
4505 4505 TRACE(req, res,
4506 4506 "No domain in rule, and no default domain");
4507 4507 retcode = IDMAP_ERR_DOMAIN_NOTFOUND;
4508 4508 goto out;
4509 4509 }
4510 4510
4511 4511 retcode = lookup_name2sid(state->cache,
4512 4512 winname, windomain,
4513 4513 want_wuser, &canonname, &canondomain,
4514 4514 &res->id.idmap_id_u.sid.prefix,
4515 4515 &res->id.idmap_id_u.sid.rid,
4516 4516 &res->id.idtype, req, 0);
4517 4517
4518 4518 if (retcode == IDMAP_SUCCESS) {
4519 4519 break;
4520 4520 } else if (retcode == IDMAP_ERR_NOTFOUND) {
4521 4521 if (values[0][0] == '*') {
4522 4522 TRACE(req, res,
4523 4523 "%s@%s not found, continuing",
4524 4524 winname, windomain);
4525 4525 continue;
4526 4526 } else {
4527 4527 TRACE(req, res,
4528 4528 "%s@%s not found",
4529 4529 winname, windomain);
4530 4530 retcode = IDMAP_ERR_NOMAPPING;
4531 4531 }
4532 4532 } else {
4533 4533 TRACE(req, res,
4534 4534 "Looking up %s@%s error=%d",
4535 4535 winname, windomain, retcode);
4536 4536 }
4537 4537
4538 4538 idmap_namerule_set(rule, values[1],
4539 4539 values[0], values[4], is_user,
4540 4540 strtol(values[3], &end, 10),
4541 4541 strtol(values[5], &end, 10),
4542 4542 direction);
4543 4543
4544 4544 goto out;
4545 4545
4546 4546 } else if (r == SQLITE_DONE) {
4547 4547 TRACE(req, res, "No matching rule");
4548 4548 retcode = IDMAP_ERR_NOTFOUND;
4549 4549 goto out;
4550 4550 } else {
4551 4551 (void) sqlite_finalize(vm, &errmsg);
4552 4552 vm = NULL;
4553 4553 idmapdlog(LOG_ERR, "%s: database error (%s)", me,
4554 4554 CHECK_NULL(errmsg));
4555 4555 sqlite_freemem(errmsg);
4556 4556 retcode = IDMAP_ERR_INTERNAL;
4557 4557 goto out;
4558 4558 }
4559 4559 }
4560 4560
4561 4561 if (values[2] != NULL)
4562 4562 res->direction =
4563 4563 (strtol(values[2], &end, 10) == 0)?
4564 4564 IDMAP_DIRECTION_U2W:IDMAP_DIRECTION_BI;
4565 4565 else
4566 4566 res->direction = IDMAP_DIRECTION_U2W;
4567 4567
4568 4568 req->id2name = canonname;
4569 4569 req->id2domain = canondomain;
4570 4570
4571 4571 idmap_namerule_set(rule, values[1], values[0], values[4],
4572 4572 is_user, strtol(values[3], &end, 10),
4573 4573 strtol(values[5], &end, 10),
4574 4574 rule->direction);
4575 4575 TRACE(req, res, "Windows name found");
4576 4576
4577 4577 out:
4578 4578 if (sql != NULL)
4579 4579 sqlite_freemem(sql);
4580 4580
4581 4581 if (retcode != IDMAP_ERR_NOTFOUND) {
4582 4582 res->info.how.map_type = IDMAP_MAP_TYPE_RULE_BASED;
4583 4583 res->info.src = IDMAP_MAP_SRC_NEW;
4584 4584 }
4585 4585
4586 4586 if (vm != NULL)
4587 4587 (void) sqlite_finalize(vm, NULL);
4588 4588 return (retcode);
4589 4589 }
4590 4590
4591 4591 /*
4592 4592 * Convention when processing unix2win requests:
4593 4593 *
4594 4594 * Unix identity:
4595 4595 * req->id1name =
4596 4596 * unixname if given otherwise unixname found will be placed
4597 4597 * here.
4598 4598 * req->id1domain =
4599 4599 * NOT USED
4600 4600 * req->id1.idtype =
4601 4601 * Given type (IDMAP_UID or IDMAP_GID)
4602 4602 * req->id1..[uid or gid] =
4603 4603 * UID/GID if given otherwise UID/GID found will be placed here.
4604 4604 *
4605 4605 * Windows identity:
4606 4606 * req->id2name =
4607 4607 * winname found will be placed here.
4608 4608 * req->id2domain =
4609 4609 * windomain found will be placed here.
4610 4610 * res->id.idtype =
4611 4611 * Target type initialized from req->id2.idtype. If
4612 4612 * it is IDMAP_SID then actual type (IDMAP_USID/GSID) found
4613 4613 * will be placed here.
4614 4614 * req->id..sid.[prefix, rid] =
4615 4615 * SID found will be placed here.
4616 4616 *
4617 4617 * Others:
4618 4618 * res->retcode =
4619 4619 * Return status for this request will be placed here.
4620 4620 * res->direction =
4621 4621 * Direction found will be placed here. Direction
4622 4622 * meaning whether the resultant mapping is valid
4623 4623 * only from unix2win or bi-directional.
4624 4624 * req->direction =
4625 4625 * INTERNAL USE. Used by idmapd to set various
4626 4626 * flags (_IDMAP_F_xxxx) to aid in processing
4627 4627 * of the request.
4628 4628 * req->id2.idtype =
4629 4629 * INTERNAL USE. Initially this is the requested target
4630 4630 * type and is used to initialize res->id.idtype.
4631 4631 * ad_lookup_batch() uses this field temporarily to store
4632 4632 * sid_type obtained by the batched AD lookups and after
4633 4633 * use resets it to IDMAP_NONE to prevent xdr from
4634 4634 * mis-interpreting the contents of req->id2.
4635 4635 * req->id2..[uid or gid or sid] =
4636 4636 * NOT USED
4637 4637 */
4638 4638
4639 4639 /*
4640 4640 * This function does the following:
4641 4641 * 1. Lookup well-known SIDs table.
4642 4642 * 2. Lookup cache.
4643 4643 * 3. Check if the client does not want new mapping to be allocated
4644 4644 * in which case this pass is the final pass.
4645 4645 * 4. Set AD/NLDAP lookup flags if it determines that the next stage needs
4646 4646 * to do AD/NLDAP lookup.
4647 4647 */
4648 4648 idmap_retcode
4649 4649 pid2sid_first_pass(lookup_state_t *state, idmap_mapping *req,
4650 4650 idmap_id_res *res, int is_user)
4651 4651 {
4652 4652 idmap_retcode retcode;
4653 4653 idmap_retcode retcode2;
4654 4654 bool_t gen_localsid_on_err = FALSE;
4655 4655
4656 4656 /* Initialize result */
4657 4657 res->id.idtype = req->id2.idtype;
4658 4658 res->direction = IDMAP_DIRECTION_UNDEF;
4659 4659
4660 4660 if (req->id2.idmap_id_u.sid.prefix != NULL) {
4661 4661 /* sanitize sidprefix */
4662 4662 free(req->id2.idmap_id_u.sid.prefix);
4663 4663 req->id2.idmap_id_u.sid.prefix = NULL;
4664 4664 }
4665 4665
4666 4666 /* Find pid */
4667 4667 if (req->id1.idmap_id_u.uid == IDMAP_SENTINEL_PID) {
4668 4668 if (req->id1name == NULL) {
4669 4669 retcode = IDMAP_ERR_ARG;
4670 4670 goto out;
4671 4671 }
4672 4672
4673 4673 retcode = ns_lookup_byname(req->id1name, NULL, &req->id1);
4674 4674 if (retcode != IDMAP_SUCCESS) {
4675 4675 TRACE(req, res, "Getting UNIX ID error=%d", retcode);
4676 4676 retcode = IDMAP_ERR_NOMAPPING;
4677 4677 goto out;
4678 4678 }
4679 4679 TRACE(req, res, "Found UNIX ID");
4680 4680 }
4681 4681
4682 4682 /* Lookup in well-known SIDs table */
4683 4683 retcode = lookup_wksids_pid2sid(req, res, is_user);
4684 4684 if (retcode == IDMAP_SUCCESS) {
4685 4685 TRACE(req, res, "Hardwired mapping");
4686 4686 goto out;
4687 4687 } else if (retcode != IDMAP_ERR_NOTFOUND) {
4688 4688 TRACE(req, res,
4689 4689 "Well-known account lookup error=%d", retcode);
4690 4690 goto out;
4691 4691 }
4692 4692
4693 4693 /* Lookup in cache */
4694 4694 retcode = lookup_cache_pid2sid(state->cache, req, res, is_user);
4695 4695 if (retcode == IDMAP_SUCCESS) {
4696 4696 TRACE(req, res, "Found in mapping cache");
4697 4697 goto out;
4698 4698 } else if (retcode != IDMAP_ERR_NOTFOUND) {
4699 4699 TRACE(req, res,
4700 4700 "Mapping cache lookup error=%d", retcode);
4701 4701 goto out;
4702 4702 }
4703 4703 TRACE(req, res, "Not found in mapping cache");
4704 4704
4705 4705 /* Ephemeral ids cannot be allocated during pid2sid */
4706 4706 if (IDMAP_ID_IS_EPHEMERAL(req->id1.idmap_id_u.uid)) {
4707 4707 retcode = IDMAP_ERR_NOMAPPING;
4708 4708 TRACE(req, res, "Shouldn't have an ephemeral ID here");
4709 4709 goto out;
4710 4710 }
4711 4711
4712 4712 if (DO_NOT_ALLOC_NEW_ID_MAPPING(req)) {
4713 4713 retcode = IDMAP_ERR_NONE_GENERATED;
4714 4714 goto out;
4715 4715 }
4716 4716
4717 4717 if (AVOID_NAMESERVICE(req)) {
4718 4718 gen_localsid_on_err = TRUE;
4719 4719 retcode = IDMAP_ERR_NOMAPPING;
4720 4720 goto out;
4721 4721 }
4722 4722
4723 4723 /* Set flags for the next stage */
4724 4724 if (state->directory_based_mapping == DIRECTORY_MAPPING_IDMU) {
4725 4725 req->direction |= _IDMAP_F_LOOKUP_AD;
4726 4726 state->ad_nqueries++;
4727 4727 } else if (AD_MODE(req->id1.idtype, state)) {
4728 4728 /*
4729 4729 * If AD-based name mapping is enabled then the next stage
4730 4730 * will need to lookup AD using unixname to get the
4731 4731 * corresponding winname.
4732 4732 */
4733 4733 if (req->id1name == NULL) {
4734 4734 /* Get unixname if only pid is given. */
4735 4735 retcode = ns_lookup_bypid(req->id1.idmap_id_u.uid,
4736 4736 is_user, &req->id1name);
4737 4737 if (retcode != IDMAP_SUCCESS) {
4738 4738 TRACE(req, res,
4739 4739 "Getting UNIX name error=%d", retcode);
4740 4740 gen_localsid_on_err = TRUE;
4741 4741 goto out;
4742 4742 }
4743 4743 TRACE(req, res, "Found UNIX name");
4744 4744 }
4745 4745 req->direction |= _IDMAP_F_LOOKUP_AD;
4746 4746 state->ad_nqueries++;
4747 4747 } else if (NLDAP_OR_MIXED_MODE(req->id1.idtype, state)) {
4748 4748 /*
4749 4749 * If native LDAP or mixed mode is enabled for name mapping
4750 4750 * then the next stage will need to lookup native LDAP using
4751 4751 * unixname/pid to get the corresponding winname.
4752 4752 */
4753 4753 req->direction |= _IDMAP_F_LOOKUP_NLDAP;
4754 4754 state->nldap_nqueries++;
4755 4755 }
4756 4756
4757 4757 /*
4758 4758 * Failed to find non-expired entry in cache. Set the flag to
4759 4759 * indicate that we are not done yet.
4760 4760 */
4761 4761 state->pid2sid_done = FALSE;
4762 4762 req->direction |= _IDMAP_F_NOTDONE;
4763 4763 retcode = IDMAP_SUCCESS;
4764 4764
4765 4765 out:
4766 4766 res->retcode = idmap_stat4prot(retcode);
4767 4767 if (ARE_WE_DONE(req->direction) && res->retcode != IDMAP_SUCCESS) {
4768 4768 if (gen_localsid_on_err == TRUE) {
4769 4769 retcode2 = generate_localsid(req, res, is_user, TRUE);
4770 4770 if (retcode2 == IDMAP_SUCCESS)
4771 4771 TRACE(req, res, "Generate local SID");
4772 4772 else
4773 4773 TRACE(req, res,
4774 4774 "Generate local SID error=%d", retcode2);
4775 4775 }
4776 4776 }
4777 4777 return (retcode);
4778 4778 }
4779 4779
4780 4780 idmap_retcode
4781 4781 pid2sid_second_pass(lookup_state_t *state, idmap_mapping *req,
4782 4782 idmap_id_res *res, int is_user)
4783 4783 {
4784 4784 bool_t gen_localsid_on_err = TRUE;
4785 4785 idmap_retcode retcode = IDMAP_SUCCESS;
4786 4786 idmap_retcode retcode2;
4787 4787
4788 4788 /* Check if second pass is needed */
4789 4789 if (ARE_WE_DONE(req->direction))
4790 4790 return (res->retcode);
4791 4791
4792 4792 /* Get status from previous pass */
4793 4793 retcode = res->retcode;
4794 4794 if (retcode != IDMAP_SUCCESS)
4795 4795 goto out;
4796 4796
4797 4797 /*
4798 4798 * If directory-based name mapping is enabled then the winname
4799 4799 * may already have been retrieved from the AD object (AD-mode)
4800 4800 * or from native LDAP object (nldap-mode or mixed-mode).
4801 4801 * Note that if we have winname but no SID then it's an error
4802 4802 * because this implies that the Native LDAP entry contains
4803 4803 * winname which does not exist and it's better that we return
4804 4804 * an error instead of doing rule-based mapping so that the user
4805 4805 * can detect the issue and take appropriate action.
4806 4806 */
4807 4807 if (req->id2name != NULL) {
4808 4808 /* Return notfound if we've winname but no SID. */
4809 4809 if (res->id.idmap_id_u.sid.prefix == NULL) {
4810 4810 TRACE(req, res, "Windows name but no SID");
4811 4811 retcode = IDMAP_ERR_NOTFOUND;
4812 4812 goto out;
4813 4813 }
4814 4814 if (state->directory_based_mapping == DIRECTORY_MAPPING_IDMU)
4815 4815 res->direction = IDMAP_DIRECTION_BI;
4816 4816 else if (AD_MODE(req->id1.idtype, state))
4817 4817 res->direction = IDMAP_DIRECTION_BI;
4818 4818 else if (NLDAP_MODE(req->id1.idtype, state))
4819 4819 res->direction = IDMAP_DIRECTION_BI;
4820 4820 else if (MIXED_MODE(req->id1.idtype, state))
4821 4821 res->direction = IDMAP_DIRECTION_W2U;
4822 4822 goto out;
4823 4823 } else if (res->id.idmap_id_u.sid.prefix != NULL) {
4824 4824 /*
4825 4825 * We've SID but no winname. This is fine because
4826 4826 * the caller may have only requested SID.
4827 4827 */
4828 4828 goto out;
4829 4829 }
4830 4830
4831 4831 /* Free any mapping info from Directory based mapping */
4832 4832 if (res->info.how.map_type != IDMAP_MAP_TYPE_UNKNOWN)
4833 4833 idmap_how_clear(&res->info.how);
4834 4834
4835 4835 if (req->id1name == NULL) {
4836 4836 /* Get unixname from name service */
4837 4837 retcode = ns_lookup_bypid(req->id1.idmap_id_u.uid, is_user,
4838 4838 &req->id1name);
4839 4839 if (retcode != IDMAP_SUCCESS) {
4840 4840 TRACE(req, res,
4841 4841 "Getting UNIX name error=%d", retcode);
4842 4842 goto out;
4843 4843 }
4844 4844 TRACE(req, res, "Found UNIX name");
4845 4845 } else if (req->id1.idmap_id_u.uid == IDMAP_SENTINEL_PID) {
4846 4846 /* Get pid from name service */
4847 4847 retcode = ns_lookup_byname(req->id1name, NULL, &req->id1);
4848 4848 if (retcode != IDMAP_SUCCESS) {
4849 4849 TRACE(req, res,
4850 4850 "Getting UNIX ID error=%d", retcode);
4851 4851 gen_localsid_on_err = FALSE;
4852 4852 goto out;
4853 4853 }
4854 4854 TRACE(req, res, "Found UNIX ID");
4855 4855 }
4856 4856
4857 4857 /* Use unixname to evaluate local name-based mapping rules */
4858 4858 retcode = name_based_mapping_pid2sid(state, req->id1name, is_user,
4859 4859 req, res);
4860 4860 if (retcode == IDMAP_ERR_NOTFOUND) {
4861 4861 retcode = generate_localsid(req, res, is_user, FALSE);
4862 4862 if (retcode == IDMAP_SUCCESS) {
4863 4863 TRACE(req, res, "Generated local SID");
4864 4864 } else {
4865 4865 TRACE(req, res,
4866 4866 "Generating local SID error=%d", retcode);
4867 4867 }
4868 4868 gen_localsid_on_err = FALSE;
4869 4869 }
4870 4870
4871 4871 out:
4872 4872 res->retcode = idmap_stat4prot(retcode);
4873 4873 if (res->retcode != IDMAP_SUCCESS) {
4874 4874 req->direction = _IDMAP_F_DONE;
4875 4875 free(req->id2name);
4876 4876 req->id2name = NULL;
4877 4877 free(req->id2domain);
4878 4878 req->id2domain = NULL;
4879 4879 if (gen_localsid_on_err == TRUE) {
4880 4880 retcode2 = generate_localsid(req, res, is_user, TRUE);
4881 4881 if (retcode2 == IDMAP_SUCCESS)
4882 4882 TRACE(req, res, "Generate local SID");
4883 4883 else
4884 4884 TRACE(req, res,
4885 4885 "Generate local SID error=%d", retcode2);
4886 4886 } else {
4887 4887 res->id.idtype = is_user ? IDMAP_USID : IDMAP_GSID;
4888 4888 }
4889 4889 }
4890 4890 if (!ARE_WE_DONE(req->direction))
4891 4891 state->pid2sid_done = FALSE;
4892 4892 return (retcode);
4893 4893 }
4894 4894
4895 4895 idmap_retcode
4896 4896 idmap_cache_flush(idmap_flush_op op)
4897 4897 {
4898 4898 idmap_retcode rc;
4899 4899 sqlite *cache = NULL;
4900 4900 char *sql1;
4901 4901 char *sql2;
4902 4902
4903 4903 switch (op) {
4904 4904 case IDMAP_FLUSH_EXPIRE:
4905 4905 sql1 =
4906 4906 "UPDATE idmap_cache SET expiration=1 WHERE expiration>0;";
4907 4907 sql2 =
4908 4908 "UPDATE name_cache SET expiration=1 WHERE expiration>0;";
4909 4909 break;
4910 4910
4911 4911 case IDMAP_FLUSH_DELETE:
4912 4912 sql1 = "DELETE FROM idmap_cache;";
4913 4913 sql2 = "DELETE FROM name_cache;";
4914 4914 break;
4915 4915
4916 4916 default:
4917 4917 return (IDMAP_ERR_INTERNAL);
4918 4918 }
4919 4919
4920 4920 rc = get_cache_handle(&cache);
4921 4921 if (rc != IDMAP_SUCCESS)
4922 4922 return (rc);
4923 4923
4924 4924 /*
4925 4925 * Note that we flush the idmapd cache first, before the kernel
4926 4926 * cache. If we did it the other way 'round, a request could come
4927 4927 * in after the kernel cache flush and pull a soon-to-be-flushed
4928 4928 * idmapd cache entry back into the kernel cache. This way the
4929 4929 * worst that will happen is that a new entry will be added to
4930 4930 * the kernel cache and then immediately flushed.
4931 4931 */
4932 4932
4933 4933 rc = sql_exec_no_cb(cache, IDMAP_CACHENAME, sql1);
4934 4934 if (rc != IDMAP_SUCCESS)
4935 4935 return (rc);
4936 4936
4937 4937 rc = sql_exec_no_cb(cache, IDMAP_CACHENAME, sql2);
4938 4938
4939 4939 (void) __idmap_flush_kcache();
4940 4940 return (rc);
4941 4941 }
↓ open down ↓ |
4572 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX