6
Copyright (C) Simo Sorce <ssorce@redhat.com> 2008-2009
8
This program is free software; you can redistribute it and/or modify
9
it under the terms of the GNU General Public License as published by
10
the Free Software Foundation; either version 3 of the License, or
11
(at your option) any later version.
13
This program is distributed in the hope that it will be useful,
14
but WITHOUT ANY WARRANTY; without even the implied warranty of
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
GNU General Public License for more details.
18
You should have received a copy of the GNU General Public License
19
along with this program. If not, see <http://www.gnu.org/licenses/>.
28
#include <security/pam_appl.h>
29
#include <security/pam_modules.h>
31
#include "util/util.h"
32
#include "providers/dp_backend.h"
35
struct proxy_nss_ops {
36
enum nss_status (*getpwnam_r)(const char *name, struct passwd *result,
37
char *buffer, size_t buflen, int *errnop);
38
enum nss_status (*getpwuid_r)(uid_t uid, struct passwd *result,
39
char *buffer, size_t buflen, int *errnop);
40
enum nss_status (*setpwent)(void);
41
enum nss_status (*getpwent_r)(struct passwd *result,
42
char *buffer, size_t buflen, int *errnop);
43
enum nss_status (*endpwent)(void);
45
enum nss_status (*getgrnam_r)(const char *name, struct group *result,
46
char *buffer, size_t buflen, int *errnop);
47
enum nss_status (*getgrgid_r)(gid_t gid, struct group *result,
48
char *buffer, size_t buflen, int *errnop);
49
enum nss_status (*setgrent)(void);
50
enum nss_status (*getgrent_r)(struct group *result,
51
char *buffer, size_t buflen, int *errnop);
52
enum nss_status (*endgrent)(void);
53
enum nss_status (*initgroups_dyn)(const char *user, gid_t group,
54
long int *start, long int *size,
55
gid_t **groups, long int limit,
61
int entry_cache_timeout;
62
struct proxy_nss_ops ops;
65
struct proxy_auth_ctx {
71
uint32_t authtok_size;
75
static int proxy_internal_conv(int num_msg, const struct pam_message **msgm,
76
struct pam_response **response,
79
struct pam_response *reply;
80
struct authtok_conv *auth_data;
82
auth_data = talloc_get_type(appdata_ptr, struct authtok_conv);
84
if (num_msg <= 0) return PAM_CONV_ERR;
86
reply = (struct pam_response *) calloc(num_msg,
87
sizeof(struct pam_response));
88
if (reply == NULL) return PAM_CONV_ERR;
90
for (i=0; i < num_msg; i++) {
91
switch( msgm[i]->msg_style ) {
92
case PAM_PROMPT_ECHO_OFF:
93
DEBUG(4, ("Conversation message: [%s]\n", msgm[i]->msg));
94
reply[i].resp_retcode = 0;
95
reply[i].resp = calloc(auth_data->authtok_size + 1,
97
if (reply[i].resp == NULL) goto failed;
98
memcpy(reply[i].resp, auth_data->authtok, auth_data->authtok_size);
102
DEBUG(1, ("Conversation style %d not supported.\n",
103
msgm[i]->msg_style));
118
static void proxy_pam_handler_cache_done(struct tevent_req *treq);
119
static void proxy_reply(struct be_req *req, int dp_err,
120
int error, const char *errstr);
122
static void proxy_pam_handler(struct be_req *req) {
125
pam_handle_t *pamh=NULL;
126
struct authtok_conv *auth_data;
127
struct pam_conv conv;
129
struct proxy_auth_ctx *ctx;;
130
bool cache_auth_data = false;
132
pd = talloc_get_type(req->req_data, struct pam_data);
135
case SSS_PAM_AUTHENTICATE:
136
ctx = talloc_get_type(req->be_ctx->bet_info[BET_AUTH].pvt_bet_data,
137
struct proxy_auth_ctx);
139
case SSS_PAM_CHAUTHTOK:
140
case SSS_PAM_CHAUTHTOK_PRELIM:
141
ctx = talloc_get_type(req->be_ctx->bet_info[BET_CHPASS].pvt_bet_data,
142
struct proxy_auth_ctx);
144
case SSS_PAM_ACCT_MGMT:
145
ctx = talloc_get_type(req->be_ctx->bet_info[BET_ACCESS].pvt_bet_data,
146
struct proxy_auth_ctx);
149
DEBUG(1, ("Unsupported PAM task.\n"));
150
pd->pam_status = PAM_SUCCESS;
151
proxy_reply(req, DP_ERR_OK, PAM_SUCCESS, NULL);
155
conv.conv=proxy_internal_conv;
156
auth_data = talloc_zero(req, struct authtok_conv);
157
conv.appdata_ptr=auth_data;
159
ret = pam_start(ctx->pam_target, pd->user, &conv, &pamh);
160
if (ret == PAM_SUCCESS) {
161
DEBUG(1, ("Pam transaction started.\n"));
162
ret = pam_set_item(pamh, PAM_TTY, pd->tty);
163
if (ret != PAM_SUCCESS) {
164
DEBUG(1, ("Setting PAM_TTY failed: %s.\n", pam_strerror(pamh, ret)));
166
ret = pam_set_item(pamh, PAM_RUSER, pd->ruser);
167
if (ret != PAM_SUCCESS) {
168
DEBUG(1, ("Setting PAM_RUSER failed: %s.\n", pam_strerror(pamh, ret)));
170
ret = pam_set_item(pamh, PAM_RHOST, pd->rhost);
171
if (ret != PAM_SUCCESS) {
172
DEBUG(1, ("Setting PAM_RHOST failed: %s.\n", pam_strerror(pamh, ret)));
175
case SSS_PAM_AUTHENTICATE:
176
auth_data->authtok_size = pd->authtok_size;
177
auth_data->authtok = pd->authtok;
178
pam_status = pam_authenticate(pamh, 0);
179
if ((pam_status == PAM_SUCCESS) &&
180
(req->be_ctx->domain->cache_credentials)) {
181
cache_auth_data = true;
184
case SSS_PAM_SETCRED:
185
pam_status=pam_setcred(pamh, 0);
187
case SSS_PAM_ACCT_MGMT:
188
pam_status=pam_acct_mgmt(pamh, 0);
190
case SSS_PAM_OPEN_SESSION:
191
pam_status=pam_open_session(pamh, 0);
193
case SSS_PAM_CLOSE_SESSION:
194
pam_status=pam_close_session(pamh, 0);
196
case SSS_PAM_CHAUTHTOK:
198
auth_data->authtok_size = pd->authtok_size;
199
auth_data->authtok = pd->authtok;
200
pam_status = pam_authenticate(pamh, 0);
201
if (pam_status != PAM_SUCCESS) break;
203
auth_data->authtok_size = pd->newauthtok_size;
204
auth_data->authtok = pd->newauthtok;
205
pam_status = pam_chauthtok(pamh, 0);
206
if ((pam_status == PAM_SUCCESS) &&
207
(req->be_ctx->domain->cache_credentials)) {
208
cache_auth_data = true;
211
case SSS_PAM_CHAUTHTOK_PRELIM:
213
auth_data->authtok_size = pd->authtok_size;
214
auth_data->authtok = pd->authtok;
215
pam_status = pam_authenticate(pamh, 0);
217
pam_status = PAM_SUCCESS;
221
DEBUG(1, ("unknown PAM call"));
222
pam_status=PAM_ABORT;
225
DEBUG(4, ("Pam result: [%d][%s]\n", pam_status,
226
pam_strerror(pamh, pam_status)));
228
if (pam_status == PAM_AUTHINFO_UNAVAIL) {
229
be_mark_offline(req->be_ctx);
232
ret = pam_end(pamh, pam_status);
233
if (ret != PAM_SUCCESS) {
235
DEBUG(1, ("Cannot terminate pam transaction.\n"));
239
DEBUG(1, ("Failed to initialize pam transaction.\n"));
240
pam_status = PAM_SYSTEM_ERR;
243
pd->pam_status = pam_status;
245
if (cache_auth_data) {
246
struct tevent_req *subreq;
249
password = talloc_size(req, auth_data->authtok_size + 1);
251
/* password caching failures are not fatal errors */
252
return proxy_reply(req, DP_ERR_OK, EOK, NULL);
254
memcpy(password, auth_data->authtok, auth_data->authtok_size);
255
password[auth_data->authtok_size] = '\0';
256
talloc_set_destructor((TALLOC_CTX *)password, password_destructor);
258
subreq = sysdb_cache_password_send(req, req->be_ctx->ev,
259
req->be_ctx->sysdb, NULL,
263
/* password caching failures are not fatal errors */
264
return proxy_reply(req, DP_ERR_OK, EOK, NULL);
266
tevent_req_set_callback(subreq, proxy_pam_handler_cache_done, req);
269
proxy_reply(req, DP_ERR_OK, EOK, NULL);
272
static void proxy_pam_handler_cache_done(struct tevent_req *subreq)
274
struct be_req *req = tevent_req_callback_data(subreq, struct be_req);
277
/* password caching failures are not fatal errors */
278
ret = sysdb_cache_password_recv(subreq);
279
talloc_zfree(subreq);
281
/* so we just log it any return */
283
DEBUG(2, ("Failed to cache password (%d)[%s]!?\n",
284
ret, strerror(ret)));
287
return proxy_reply(req, DP_ERR_OK, EOK, NULL);
290
static void proxy_reply(struct be_req *req, int dp_err,
291
int error, const char *errstr)
293
return req->fn(req, dp_err, error, errstr);
296
/* =Common-proxy-tevent_req-utils=========================================*/
298
#define DEFAULT_BUFSIZE 4096
299
#define MAX_BUF_SIZE 1024*1024 /* max 1MiB */
302
struct tevent_context *ev;
303
struct proxy_ctx *ctx;
304
struct sysdb_ctx *sysdb;
305
struct sss_domain_info *domain;
308
struct sysdb_handle *handle;
315
static void proxy_default_done(struct tevent_req *subreq)
317
struct tevent_req *req = tevent_req_callback_data(subreq,
321
ret = sysdb_transaction_commit_recv(subreq);
322
talloc_zfree(subreq);
324
tevent_req_error(req, ret);
328
tevent_req_done(req);
331
static int proxy_default_recv(struct tevent_req *req)
333
TEVENT_REQ_RETURN_ON_ERROR(req);
339
/* =Getpwnam-wrapper======================================================*/
341
static void get_pw_name_process(struct tevent_req *subreq);
342
static void get_pw_name_remove_done(struct tevent_req *subreq);
343
static void get_pw_name_add_done(struct tevent_req *subreq);
345
static struct tevent_req *get_pw_name_send(TALLOC_CTX *mem_ctx,
346
struct tevent_context *ev,
347
struct proxy_ctx *ctx,
348
struct sysdb_ctx *sysdb,
349
struct sss_domain_info *domain,
352
struct tevent_req *req, *subreq;
353
struct proxy_state *state;
355
req = tevent_req_create(mem_ctx, &state, struct proxy_state);
356
if (!req) return NULL;
358
memset(state, 0, sizeof(struct proxy_state));
362
state->sysdb = sysdb;
363
state->domain = domain;
366
subreq = sysdb_transaction_send(state, state->ev, state->sysdb);
371
tevent_req_set_callback(subreq, get_pw_name_process, req);
376
static void get_pw_name_process(struct tevent_req *subreq)
378
struct tevent_req *req = tevent_req_callback_data(subreq,
380
struct proxy_state *state = tevent_req_data(req,
382
struct proxy_ctx *ctx = state->ctx;
383
struct sss_domain_info *dom = ctx->be->domain;
384
enum nss_status status;
387
bool delete_user = false;
390
DEBUG(7, ("Searching user by name (%s)\n", state->name));
392
ret = sysdb_transaction_recv(subreq, state, &state->handle);
394
tevent_req_error(req, ret);
397
talloc_zfree(subreq);
399
state->pwd = talloc(state, struct passwd);
401
tevent_req_error(req, ENOMEM);
405
buflen = DEFAULT_BUFSIZE;
406
buffer = talloc_size(state, buflen);
408
tevent_req_error(req, ENOMEM);
412
/* FIXME: should we move this call outside the transaction to keep the
413
* transaction as short as possible ? */
414
status = ctx->ops.getpwnam_r(state->name, state->pwd,
415
buffer, buflen, &ret);
418
case NSS_STATUS_NOTFOUND:
420
DEBUG(7, ("User %s not found.\n", state->name));
424
case NSS_STATUS_SUCCESS:
426
DEBUG(7, ("User %s found: (%s, %d, %d)\n",
427
state->name, state->pwd->pw_name,
428
state->pwd->pw_uid, state->pwd->pw_gid));
430
/* uid=0 or gid=0 are invalid values */
431
/* also check that the id is in the valid range for this domain */
432
if (OUT_OF_ID_RANGE(state->pwd->pw_uid, dom->id_min, dom->id_max) ||
433
OUT_OF_ID_RANGE(state->pwd->pw_gid, dom->id_min, dom->id_max)) {
435
DEBUG(2, ("User [%s] filtered out! (id out of range)\n",
441
subreq = sysdb_store_user_send(state, state->ev, state->handle,
444
state->pwd->pw_passwd,
447
state->pwd->pw_gecos,
449
state->pwd->pw_shell,
450
NULL, ctx->entry_cache_timeout);
452
tevent_req_error(req, ENOMEM);
455
tevent_req_set_callback(subreq, get_pw_name_add_done, req);
458
case NSS_STATUS_UNAVAIL:
459
/* "remote" backend unavailable. Enter offline mode */
460
tevent_req_error(req, ENXIO);
464
DEBUG(2, ("proxy -> getpwnam_r failed for '%s' <%d>\n",
465
state->name, status));
466
tevent_req_error(req, EIO);
473
DEBUG(7, ("User %s does not exist (or is invalid) on remote server,"
474
" deleting!\n", state->name));
476
dn = sysdb_user_dn(state->sysdb, state,
477
state->domain->name, state->name);
479
tevent_req_error(req, ENOMEM);
483
subreq = sysdb_delete_entry_send(state, state->ev, state->handle, dn, true);
485
tevent_req_error(req, ENOMEM);
488
tevent_req_set_callback(subreq, get_pw_name_remove_done, req);
492
static void get_pw_name_add_done(struct tevent_req *subreq)
494
struct tevent_req *req = tevent_req_callback_data(subreq,
496
struct proxy_state *state = tevent_req_data(req,
500
ret = sysdb_store_user_recv(subreq);
501
talloc_zfree(subreq);
503
tevent_req_error(req, ret);
507
subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);
509
tevent_req_error(req, ENOMEM);
512
tevent_req_set_callback(subreq, proxy_default_done, req);
515
static void get_pw_name_remove_done(struct tevent_req *subreq)
517
struct tevent_req *req = tevent_req_callback_data(subreq,
519
struct proxy_state *state = tevent_req_data(req,
523
ret = sysdb_delete_entry_recv(subreq);
524
talloc_zfree(subreq);
526
tevent_req_error(req, ret);
530
subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);
532
tevent_req_error(req, ENOMEM);
535
tevent_req_set_callback(subreq, proxy_default_done, req);
538
/* =Getpwuid-wrapper======================================================*/
540
static void get_pw_uid_process(struct tevent_req *subreq);
541
static void get_pw_uid_remove_done(struct tevent_req *subreq);
543
static struct tevent_req *get_pw_uid_send(TALLOC_CTX *mem_ctx,
544
struct tevent_context *ev,
545
struct proxy_ctx *ctx,
546
struct sysdb_ctx *sysdb,
547
struct sss_domain_info *domain,
550
struct tevent_req *req, *subreq;
551
struct proxy_state *state;
553
req = tevent_req_create(mem_ctx, &state, struct proxy_state);
554
if (!req) return NULL;
556
memset(state, 0, sizeof(struct proxy_state));
560
state->sysdb = sysdb;
561
state->domain = domain;
564
subreq = sysdb_transaction_send(state, state->ev, state->sysdb);
569
tevent_req_set_callback(subreq, get_pw_uid_process, req);
574
static void get_pw_uid_process(struct tevent_req *subreq)
576
struct tevent_req *req = tevent_req_callback_data(subreq,
578
struct proxy_state *state = tevent_req_data(req,
580
struct proxy_ctx *ctx = state->ctx;
581
struct sss_domain_info *dom = ctx->be->domain;
582
enum nss_status status;
585
bool delete_user = false;
588
DEBUG(7, ("Searching user by uid (%d)\n", state->uid));
590
ret = sysdb_transaction_recv(subreq, state, &state->handle);
592
tevent_req_error(req, ret);
595
talloc_zfree(subreq);
597
state->pwd = talloc(state, struct passwd);
599
tevent_req_error(req, ENOMEM);
603
buflen = DEFAULT_BUFSIZE;
604
buffer = talloc_size(state, buflen);
606
tevent_req_error(req, ENOMEM);
610
/* always zero out the pwd structure */
611
memset(state->pwd, 0, sizeof(struct passwd));
613
status = ctx->ops.getpwuid_r(state->uid, state->pwd,
614
buffer, buflen, &ret);
617
case NSS_STATUS_NOTFOUND:
619
DEBUG(7, ("User %d not found.\n", state->uid));
623
case NSS_STATUS_SUCCESS:
625
DEBUG(7, ("User %d found (%s, %d, %d)\n",
626
state->uid, state->pwd->pw_name,
627
state->pwd->pw_uid, state->pwd->pw_gid));
629
/* uid=0 or gid=0 are invalid values */
630
/* also check that the id is in the valid range for this domain */
631
if (OUT_OF_ID_RANGE(state->pwd->pw_uid, dom->id_min, dom->id_max) ||
632
OUT_OF_ID_RANGE(state->pwd->pw_gid, dom->id_min, dom->id_max)) {
634
DEBUG(2, ("User [%s] filtered out! (id out of range)\n",
640
subreq = sysdb_store_user_send(state, state->ev, state->handle,
643
state->pwd->pw_passwd,
646
state->pwd->pw_gecos,
648
state->pwd->pw_shell,
649
NULL, ctx->entry_cache_timeout);
651
tevent_req_error(req, ENOMEM);
654
tevent_req_set_callback(subreq, get_pw_name_add_done, req);
657
case NSS_STATUS_UNAVAIL:
658
/* "remote" backend unavailable. Enter offline mode */
659
tevent_req_error(req, ENXIO);
663
DEBUG(2, ("proxy -> getpwnam_r failed for '%s' <%d>\n",
664
state->name, status));
665
tevent_req_error(req, EIO);
670
DEBUG(7, ("User %d does not exist (or is invalid) on remote server,"
671
" deleting!\n", state->uid));
673
subreq = sysdb_delete_user_send(state, state->ev,
678
tevent_req_error(req, ENOMEM);
681
tevent_req_set_callback(subreq, get_pw_uid_remove_done, req);
685
static void get_pw_uid_remove_done(struct tevent_req *subreq)
687
struct tevent_req *req = tevent_req_callback_data(subreq,
689
struct proxy_state *state = tevent_req_data(req,
693
ret = sysdb_delete_user_recv(subreq);
694
talloc_zfree(subreq);
695
if (ret && ret != ENOENT) {
696
tevent_req_error(req, ret);
700
subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);
702
tevent_req_error(req, ENOMEM);
705
tevent_req_set_callback(subreq, proxy_default_done, req);
708
/* =Getpwent-wrapper======================================================*/
710
struct enum_users_state {
711
struct tevent_context *ev;
712
struct proxy_ctx *ctx;
713
struct sysdb_ctx *sysdb;
714
struct sss_domain_info *domain;
715
struct sysdb_handle *handle;
725
static void enum_users_process(struct tevent_req *subreq);
727
static struct tevent_req *enum_users_send(TALLOC_CTX *mem_ctx,
728
struct tevent_context *ev,
729
struct proxy_ctx *ctx,
730
struct sysdb_ctx *sysdb,
731
struct sss_domain_info *domain)
733
struct tevent_req *req, *subreq;
734
struct enum_users_state *state;
735
enum nss_status status;
737
DEBUG(7, ("Enumerating users\n"));
739
req = tevent_req_create(mem_ctx, &state, struct enum_users_state);
740
if (!req) return NULL;
744
state->sysdb = sysdb;
745
state->domain = domain;
746
state->handle = NULL;
748
state->pwd = talloc(state, struct passwd);
750
tevent_req_error(req, ENOMEM);
754
state->buflen = DEFAULT_BUFSIZE;
755
state->buffer = talloc_size(state, state->buflen);
756
if (!state->buffer) {
757
tevent_req_error(req, ENOMEM);
761
state->in_transaction = false;
763
status = ctx->ops.setpwent();
764
if (status != NSS_STATUS_SUCCESS) {
765
tevent_req_error(req, EIO);
769
subreq = sysdb_transaction_send(state, state->ev, state->sysdb);
771
tevent_req_error(req, ENOMEM);
774
tevent_req_set_callback(subreq, enum_users_process, req);
779
tevent_req_post(req, ev);
783
static void enum_users_process(struct tevent_req *subreq)
785
struct tevent_req *req = tevent_req_callback_data(subreq,
787
struct enum_users_state *state = tevent_req_data(req,
788
struct enum_users_state);
789
struct proxy_ctx *ctx = state->ctx;
790
struct sss_domain_info *dom = ctx->be->domain;
791
enum nss_status status;
795
if (!state->in_transaction) {
796
ret = sysdb_transaction_recv(subreq, state, &state->handle);
800
talloc_zfree(subreq);
802
state->in_transaction = true;
804
ret = sysdb_store_user_recv(subreq);
806
/* Do not fail completely on errors.
807
* Just report the failure to save and go on */
808
DEBUG(2, ("Failed to store user. Ignoring.\n"));
810
talloc_zfree(subreq);
814
/* always zero out the pwd structure */
815
memset(state->pwd, 0, sizeof(struct passwd));
818
status = ctx->ops.getpwent_r(state->pwd,
819
state->buffer, state->buflen, &ret);
822
case NSS_STATUS_TRYAGAIN:
823
/* buffer too small ? */
824
if (state->buflen < MAX_BUF_SIZE) {
827
if (state->buflen > MAX_BUF_SIZE) {
828
state->buflen = MAX_BUF_SIZE;
830
newbuf = talloc_realloc_size(state, state->buffer, state->buflen);
835
state->buffer = newbuf;
838
case NSS_STATUS_NOTFOUND:
840
/* we are done here */
841
DEBUG(7, ("Enumeration completed.\n"));
844
subreq = sysdb_transaction_commit_send(state, state->ev,
847
tevent_req_error(req, ENOMEM);
850
tevent_req_set_callback(subreq, proxy_default_done, req);
853
case NSS_STATUS_SUCCESS:
855
DEBUG(7, ("User found (%s, %d, %d)\n", state->pwd->pw_name,
856
state->pwd->pw_uid, state->pwd->pw_gid));
858
/* uid=0 or gid=0 are invalid values */
859
/* also check that the id is in the valid range for this domain */
860
if (OUT_OF_ID_RANGE(state->pwd->pw_uid, dom->id_min, dom->id_max) ||
861
OUT_OF_ID_RANGE(state->pwd->pw_gid, dom->id_min, dom->id_max)) {
863
DEBUG(2, ("User [%s] filtered out! (id out of range)\n",
864
state->pwd->pw_name));
866
goto again; /* skip */
869
subreq = sysdb_store_user_send(state, state->ev, state->handle,
872
state->pwd->pw_passwd,
875
state->pwd->pw_gecos,
877
state->pwd->pw_shell,
878
NULL, ctx->entry_cache_timeout);
880
tevent_req_error(req, ENOMEM);
883
tevent_req_set_callback(subreq, enum_users_process, req);
886
case NSS_STATUS_UNAVAIL:
887
/* "remote" backend unavailable. Enter offline mode */
892
DEBUG(2, ("proxy -> getpwent_r failed (%d)[%s]\n",
893
ret, strerror(ret)));
899
tevent_req_error(req, ret);
902
/* =Getgrnam-wrapper======================================================*/
904
#define DEBUG_GR_MEM(level, state) \
906
if (debug_level >= level) { \
907
if (!state->grp->gr_mem || !state->grp->gr_mem[0]) { \
908
DEBUG(level, ("Group %s has no members!\n", \
909
state->grp->gr_name)); \
912
while (state->grp->gr_mem[i]) { \
916
DEBUG(level, ("Group %s has %d members!\n", \
917
state->grp->gr_name, i)); \
922
static void get_gr_name_process(struct tevent_req *subreq);
923
static void get_gr_name_remove_done(struct tevent_req *subreq);
924
static void get_gr_name_add_done(struct tevent_req *subreq);
926
static struct tevent_req *get_gr_name_send(TALLOC_CTX *mem_ctx,
927
struct tevent_context *ev,
928
struct proxy_ctx *ctx,
929
struct sysdb_ctx *sysdb,
930
struct sss_domain_info *domain,
933
struct tevent_req *req, *subreq;
934
struct proxy_state *state;
936
req = tevent_req_create(mem_ctx, &state, struct proxy_state);
937
if (!req) return NULL;
939
memset(state, 0, sizeof(struct proxy_state));
943
state->sysdb = sysdb;
944
state->domain = domain;
947
subreq = sysdb_transaction_send(state, state->ev, state->sysdb);
952
tevent_req_set_callback(subreq, get_gr_name_process, req);
957
static void get_gr_name_process(struct tevent_req *subreq)
959
struct tevent_req *req = tevent_req_callback_data(subreq,
961
struct proxy_state *state = tevent_req_data(req,
963
struct proxy_ctx *ctx = state->ctx;
964
struct sss_domain_info *dom = ctx->be->domain;
965
enum nss_status status;
969
bool delete_group = false;
970
struct sysdb_attrs *members;
973
DEBUG(7, ("Searching group by name (%s)\n", state->name));
975
ret = sysdb_transaction_recv(subreq, state, &state->handle);
977
tevent_req_error(req, ret);
980
talloc_zfree(subreq);
982
state->grp = talloc(state, struct group);
984
tevent_req_error(req, ENOMEM);
988
buflen = DEFAULT_BUFSIZE;
989
buffer = talloc_size(state, buflen);
991
tevent_req_error(req, ENOMEM);
995
/* FIXME: should we move this call outside the transaction to keep the
996
* transaction as short as possible ? */
998
/* always zero out the grp structure */
999
memset(state->grp, 0, sizeof(struct group));
1001
status = ctx->ops.getgrnam_r(state->name, state->grp,
1002
buffer, buflen, &ret);
1005
case NSS_STATUS_TRYAGAIN:
1006
/* buffer too small ? */
1007
if (buflen < MAX_BUF_SIZE) {
1010
if (buflen > MAX_BUF_SIZE) {
1011
buflen = MAX_BUF_SIZE;
1013
newbuf = talloc_realloc_size(state, buffer, buflen);
1015
tevent_req_error(req, ENOMEM);
1021
case NSS_STATUS_NOTFOUND:
1023
DEBUG(7, ("Group %s not found.\n", state->name));
1024
delete_group = true;
1027
case NSS_STATUS_SUCCESS:
1029
DEBUG(7, ("Group %s found: (%s, %d)\n", state->name,
1030
state->grp->gr_name, state->grp->gr_gid));
1032
/* gid=0 is an invalid value */
1033
/* also check that the id is in the valid range for this domain */
1034
if (OUT_OF_ID_RANGE(state->grp->gr_gid, dom->id_min, dom->id_max)) {
1036
DEBUG(2, ("Group [%s] filtered out! (id out of range)\n",
1038
delete_group = true;
1042
DEBUG_GR_MEM(7, state);
1044
if (state->grp->gr_mem && state->grp->gr_mem[0]) {
1045
members = sysdb_new_attrs(state);
1047
tevent_req_error(req, ENOMEM);
1050
ret = sysdb_attrs_users_from_str_list(members, SYSDB_MEMBER,
1051
state->domain->name,
1052
(const char **)state->grp->gr_mem);
1054
tevent_req_error(req, ret);
1061
subreq = sysdb_store_group_send(state, state->ev, state->handle,
1063
state->grp->gr_name,
1066
ctx->entry_cache_timeout);
1068
tevent_req_error(req, ENOMEM);
1071
tevent_req_set_callback(subreq, get_gr_name_add_done, req);
1074
case NSS_STATUS_UNAVAIL:
1075
/* "remote" backend unavailable. Enter offline mode */
1076
tevent_req_error(req, ENXIO);
1080
DEBUG(2, ("proxy -> getgrnam_r failed for '%s' <%d>\n",
1081
state->name, status));
1082
tevent_req_error(req, EIO);
1089
DEBUG(7, ("Group %s does not exist (or is invalid) on remote server,"
1090
" deleting!\n", state->name));
1092
dn = sysdb_group_dn(state->sysdb, state,
1093
state->domain->name, state->name);
1095
tevent_req_error(req, ENOMEM);
1099
subreq = sysdb_delete_entry_send(state, state->ev, state->handle, dn, true);
1101
tevent_req_error(req, ENOMEM);
1104
tevent_req_set_callback(subreq, get_gr_name_remove_done, req);
1108
static void get_gr_name_add_done(struct tevent_req *subreq)
1110
struct tevent_req *req = tevent_req_callback_data(subreq,
1112
struct proxy_state *state = tevent_req_data(req,
1113
struct proxy_state);
1116
ret = sysdb_store_group_recv(subreq);
1117
talloc_zfree(subreq);
1119
tevent_req_error(req, ret);
1123
subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);
1125
tevent_req_error(req, ENOMEM);
1128
tevent_req_set_callback(subreq, proxy_default_done, req);
1131
static void get_gr_name_remove_done(struct tevent_req *subreq)
1133
struct tevent_req *req = tevent_req_callback_data(subreq,
1135
struct proxy_state *state = tevent_req_data(req,
1136
struct proxy_state);
1139
ret = sysdb_delete_entry_recv(subreq);
1140
talloc_zfree(subreq);
1142
tevent_req_error(req, ret);
1146
subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);
1148
tevent_req_error(req, ENOMEM);
1151
tevent_req_set_callback(subreq, proxy_default_done, req);
1154
/* =Getgrgid-wrapper======================================================*/
1156
static void get_gr_gid_process(struct tevent_req *subreq);
1157
static void get_gr_gid_remove_done(struct tevent_req *subreq);
1159
static struct tevent_req *get_gr_gid_send(TALLOC_CTX *mem_ctx,
1160
struct tevent_context *ev,
1161
struct proxy_ctx *ctx,
1162
struct sysdb_ctx *sysdb,
1163
struct sss_domain_info *domain,
1166
struct tevent_req *req, *subreq;
1167
struct proxy_state *state;
1169
req = tevent_req_create(mem_ctx, &state, struct proxy_state);
1170
if (!req) return NULL;
1172
memset(state, 0, sizeof(struct proxy_state));
1176
state->sysdb = sysdb;
1177
state->domain = domain;
1180
subreq = sysdb_transaction_send(state, state->ev, state->sysdb);
1185
tevent_req_set_callback(subreq, get_gr_gid_process, req);
1190
static void get_gr_gid_process(struct tevent_req *subreq)
1192
struct tevent_req *req = tevent_req_callback_data(subreq,
1194
struct proxy_state *state = tevent_req_data(req,
1195
struct proxy_state);
1196
struct proxy_ctx *ctx = state->ctx;
1197
struct sss_domain_info *dom = ctx->be->domain;
1198
enum nss_status status;
1202
bool delete_group = false;
1203
struct sysdb_attrs *members;
1206
DEBUG(7, ("Searching group by gid (%d)\n", state->gid));
1208
ret = sysdb_transaction_recv(subreq, state, &state->handle);
1210
tevent_req_error(req, ret);
1213
talloc_zfree(subreq);
1215
state->grp = talloc(state, struct group);
1217
tevent_req_error(req, ENOMEM);
1221
buflen = DEFAULT_BUFSIZE;
1222
buffer = talloc_size(state, buflen);
1224
tevent_req_error(req, ENOMEM);
1229
/* always zero out the group structure */
1230
memset(state->grp, 0, sizeof(struct group));
1232
status = ctx->ops.getgrgid_r(state->gid, state->grp,
1233
buffer, buflen, &ret);
1236
case NSS_STATUS_TRYAGAIN:
1237
/* buffer too small ? */
1238
if (buflen < MAX_BUF_SIZE) {
1241
if (buflen > MAX_BUF_SIZE) {
1242
buflen = MAX_BUF_SIZE;
1244
newbuf = talloc_realloc_size(state, buffer, buflen);
1246
tevent_req_error(req, ENOMEM);
1252
case NSS_STATUS_NOTFOUND:
1254
DEBUG(7, ("Group %d not found.\n", state->gid));
1255
delete_group = true;
1258
case NSS_STATUS_SUCCESS:
1260
DEBUG(7, ("Group %d found (%s, %d)\n", state->gid,
1261
state->grp->gr_name, state->grp->gr_gid));
1263
/* gid=0 is an invalid value */
1264
/* also check that the id is in the valid range for this domain */
1265
if (OUT_OF_ID_RANGE(state->grp->gr_gid, dom->id_min, dom->id_max)) {
1267
DEBUG(2, ("Group [%s] filtered out! (id out of range)\n",
1268
state->grp->gr_name));
1269
delete_group = true;
1273
DEBUG_GR_MEM(7, state);
1275
if (state->grp->gr_mem && state->grp->gr_mem[0]) {
1276
members = sysdb_new_attrs(state);
1278
tevent_req_error(req, ENOMEM);
1281
ret = sysdb_attrs_users_from_str_list(members, SYSDB_MEMBER,
1282
state->domain->name,
1283
(const char **)state->grp->gr_mem);
1285
tevent_req_error(req, ret);
1292
subreq = sysdb_store_group_send(state, state->ev, state->handle,
1294
state->grp->gr_name,
1297
ctx->entry_cache_timeout);
1299
tevent_req_error(req, ENOMEM);
1302
tevent_req_set_callback(subreq, get_gr_name_add_done, req);
1305
case NSS_STATUS_UNAVAIL:
1306
/* "remote" backend unavailable. Enter offline mode */
1307
tevent_req_error(req, ENXIO);
1311
DEBUG(2, ("proxy -> getgrgid_r failed for '%d' <%d>\n",
1312
state->gid, status));
1313
tevent_req_error(req, EIO);
1319
DEBUG(7, ("Group %d does not exist (or is invalid) on remote server,"
1320
" deleting!\n", state->gid));
1322
subreq = sysdb_delete_group_send(state, state->ev,
1323
NULL, state->handle,
1327
tevent_req_error(req, ENOMEM);
1330
tevent_req_set_callback(subreq, get_gr_gid_remove_done, req);
1334
static void get_gr_gid_remove_done(struct tevent_req *subreq)
1336
struct tevent_req *req = tevent_req_callback_data(subreq,
1338
struct proxy_state *state = tevent_req_data(req,
1339
struct proxy_state);
1342
ret = sysdb_delete_group_recv(subreq);
1343
talloc_zfree(subreq);
1344
if (ret && ret != ENOENT) {
1345
tevent_req_error(req, ret);
1349
subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);
1351
tevent_req_error(req, ENOMEM);
1354
tevent_req_set_callback(subreq, proxy_default_done, req);
1357
/* =Getgrent-wrapper======================================================*/
1359
struct enum_groups_state {
1360
struct tevent_context *ev;
1361
struct proxy_ctx *ctx;
1362
struct sysdb_ctx *sysdb;
1363
struct sss_domain_info *domain;
1364
struct sysdb_handle *handle;
1371
bool in_transaction;
1374
static void enum_groups_process(struct tevent_req *subreq);
1376
static struct tevent_req *enum_groups_send(TALLOC_CTX *mem_ctx,
1377
struct tevent_context *ev,
1378
struct proxy_ctx *ctx,
1379
struct sysdb_ctx *sysdb,
1380
struct sss_domain_info *domain)
1382
struct tevent_req *req, *subreq;
1383
struct enum_groups_state *state;
1384
enum nss_status status;
1386
DEBUG(7, ("Enumerating groups\n"));
1388
req = tevent_req_create(mem_ctx, &state, struct enum_groups_state);
1389
if (!req) return NULL;
1393
state->sysdb = sysdb;
1394
state->domain = domain;
1395
state->handle = NULL;
1397
state->grp = talloc(state, struct group);
1399
tevent_req_error(req, ENOMEM);
1403
state->buflen = DEFAULT_BUFSIZE;
1404
state->buffer = talloc_size(state, state->buflen);
1405
if (!state->buffer) {
1406
tevent_req_error(req, ENOMEM);
1410
state->in_transaction = false;
1412
status = ctx->ops.setgrent();
1413
if (status != NSS_STATUS_SUCCESS) {
1414
tevent_req_error(req, EIO);
1418
subreq = sysdb_transaction_send(state, state->ev, state->sysdb);
1420
tevent_req_error(req, ENOMEM);
1423
tevent_req_set_callback(subreq, enum_groups_process, req);
1428
tevent_req_post(req, ev);
1432
static void enum_groups_process(struct tevent_req *subreq)
1434
struct tevent_req *req = tevent_req_callback_data(subreq,
1436
struct enum_groups_state *state = tevent_req_data(req,
1437
struct enum_groups_state);
1438
struct proxy_ctx *ctx = state->ctx;
1439
struct sss_domain_info *dom = ctx->be->domain;
1440
enum nss_status status;
1441
struct sysdb_attrs *members;
1445
if (!state->in_transaction) {
1446
ret = sysdb_transaction_recv(subreq, state, &state->handle);
1448
tevent_req_error(req, ret);
1451
talloc_zfree(subreq);
1453
state->in_transaction = true;
1455
ret = sysdb_store_group_recv(subreq);
1457
/* Do not fail completely on errors.
1458
* Just report the failure to save and go on */
1459
DEBUG(2, ("Failed to store group. Ignoring.\n"));
1461
talloc_zfree(subreq);
1465
/* always zero out the grp structure */
1466
memset(state->grp, 0, sizeof(struct group));
1469
status = ctx->ops.getgrent_r(state->grp,
1470
state->buffer, state->buflen, &ret);
1473
case NSS_STATUS_TRYAGAIN:
1474
/* buffer too small ? */
1475
if (state->buflen < MAX_BUF_SIZE) {
1478
if (state->buflen > MAX_BUF_SIZE) {
1479
state->buflen = MAX_BUF_SIZE;
1481
newbuf = talloc_realloc_size(state, state->buffer, state->buflen);
1486
state->buffer = newbuf;
1489
case NSS_STATUS_NOTFOUND:
1491
/* we are done here */
1492
DEBUG(7, ("Enumeration completed.\n"));
1494
ctx->ops.endgrent();
1495
subreq = sysdb_transaction_commit_send(state, state->ev,
1498
tevent_req_error(req, ENOMEM);
1501
tevent_req_set_callback(subreq, proxy_default_done, req);
1504
case NSS_STATUS_SUCCESS:
1506
DEBUG(7, ("Group found (%s, %d)\n",
1507
state->grp->gr_name, state->grp->gr_gid));
1509
/* gid=0 is an invalid value */
1510
/* also check that the id is in the valid range for this domain */
1511
if (OUT_OF_ID_RANGE(state->grp->gr_gid, dom->id_min, dom->id_max)) {
1513
DEBUG(2, ("Group [%s] filtered out! (id out of range)\n",
1514
state->grp->gr_name));
1516
goto again; /* skip */
1519
DEBUG_GR_MEM(7, state);
1521
if (state->grp->gr_mem && state->grp->gr_mem[0]) {
1522
members = sysdb_new_attrs(state);
1524
tevent_req_error(req, ENOMEM);
1527
ret = sysdb_attrs_users_from_str_list(members, SYSDB_MEMBER,
1528
state->domain->name,
1529
(const char **)state->grp->gr_mem);
1531
tevent_req_error(req, ret);
1538
subreq = sysdb_store_group_send(state, state->ev, state->handle,
1540
state->grp->gr_name,
1543
ctx->entry_cache_timeout);
1545
tevent_req_error(req, ENOMEM);
1548
tevent_req_set_callback(subreq, enum_groups_process, req);
1551
case NSS_STATUS_UNAVAIL:
1552
/* "remote" backend unavailable. Enter offline mode */
1557
DEBUG(2, ("proxy -> getgrent_r failed (%d)[%s]\n",
1558
ret, strerror(ret)));
1563
ctx->ops.endgrent();
1564
tevent_req_error(req, ret);
1568
/* =Initgroups-wrapper====================================================*/
1570
static void get_initgr_process(struct tevent_req *subreq);
1571
static void get_initgr_groups_process(struct tevent_req *subreq);
1572
static void get_initgr_groups_done(struct tevent_req *subreq);
1573
static struct tevent_req *get_groups_by_gid_send(TALLOC_CTX *mem_ctx,
1574
struct tevent_context *ev,
1575
struct sysdb_handle *handle,
1576
struct proxy_ctx *ctx,
1577
struct sss_domain_info *domain,
1578
gid_t *gids, int num_gids);
1579
static int get_groups_by_gid_recv(struct tevent_req *req);
1580
static void get_groups_by_gid_process(struct tevent_req *subreq);
1581
static struct tevent_req *get_group_from_gid_send(TALLOC_CTX *mem_ctx,
1582
struct tevent_context *ev,
1583
struct sysdb_handle *handle,
1584
struct proxy_ctx *ctx,
1585
struct sss_domain_info *domain,
1587
static int get_group_from_gid_recv(struct tevent_req *req);
1588
static void get_group_from_gid_send_del_done(struct tevent_req *subreq);
1589
static void get_group_from_gid_send_add_done(struct tevent_req *subreq);
1592
static struct tevent_req *get_initgr_send(TALLOC_CTX *mem_ctx,
1593
struct tevent_context *ev,
1594
struct proxy_ctx *ctx,
1595
struct sysdb_ctx *sysdb,
1596
struct sss_domain_info *domain,
1599
struct tevent_req *req, *subreq;
1600
struct proxy_state *state;
1602
req = tevent_req_create(mem_ctx, &state, struct proxy_state);
1603
if (!req) return NULL;
1605
memset(state, 0, sizeof(struct proxy_state));
1609
state->sysdb = sysdb;
1610
state->domain = domain;
1613
subreq = sysdb_transaction_send(state, state->ev, state->sysdb);
1618
tevent_req_set_callback(subreq, get_initgr_process, req);
1623
static void get_initgr_process(struct tevent_req *subreq)
1625
struct tevent_req *req = tevent_req_callback_data(subreq,
1627
struct proxy_state *state = tevent_req_data(req,
1628
struct proxy_state);
1629
struct proxy_ctx *ctx = state->ctx;
1630
struct sss_domain_info *dom = ctx->be->domain;
1631
enum nss_status status;
1634
bool delete_user = false;
1637
ret = sysdb_transaction_recv(subreq, state, &state->handle);
1639
tevent_req_error(req, ret);
1642
talloc_zfree(subreq);
1644
state->pwd = talloc(state, struct passwd);
1646
tevent_req_error(req, ENOMEM);
1650
buflen = DEFAULT_BUFSIZE;
1651
buffer = talloc_size(state, buflen);
1653
tevent_req_error(req, ENOMEM);
1657
/* FIXME: should we move this call outside the transaction to keep the
1658
* transaction as short as possible ? */
1659
status = ctx->ops.getpwnam_r(state->name, state->pwd,
1660
buffer, buflen, &ret);
1663
case NSS_STATUS_NOTFOUND:
1668
case NSS_STATUS_SUCCESS:
1670
/* uid=0 or gid=0 are invalid values */
1671
/* also check that the id is in the valid range for this domain */
1672
if (OUT_OF_ID_RANGE(state->pwd->pw_uid, dom->id_min, dom->id_max) ||
1673
OUT_OF_ID_RANGE(state->pwd->pw_gid, dom->id_min, dom->id_max)) {
1675
DEBUG(2, ("User [%s] filtered out! (id out of range)\n",
1681
subreq = sysdb_store_user_send(state, state->ev, state->handle,
1683
state->pwd->pw_name,
1684
state->pwd->pw_passwd,
1687
state->pwd->pw_gecos,
1689
state->pwd->pw_shell,
1690
NULL, ctx->entry_cache_timeout);
1692
tevent_req_error(req, ENOMEM);
1695
tevent_req_set_callback(subreq, get_initgr_groups_process, req);
1698
case NSS_STATUS_UNAVAIL:
1699
/* "remote" backend unavailable. Enter offline mode */
1700
tevent_req_error(req, ENXIO);
1704
DEBUG(2, ("proxy -> getpwnam_r failed for '%s' <%d>\n",
1705
state->name, status));
1706
tevent_req_error(req, EIO);
1713
dn = sysdb_user_dn(state->sysdb, state,
1714
state->domain->name, state->name);
1716
tevent_req_error(req, ENOMEM);
1720
subreq = sysdb_delete_entry_send(state, state->ev, state->handle, dn, true);
1722
tevent_req_error(req, ENOMEM);
1725
tevent_req_set_callback(subreq, get_pw_name_remove_done, req);
1729
static void get_initgr_groups_process(struct tevent_req *subreq)
1731
struct tevent_req *req = tevent_req_callback_data(subreq,
1733
struct proxy_state *state = tevent_req_data(req,
1734
struct proxy_state);
1735
struct proxy_ctx *ctx = state->ctx;
1736
enum nss_status status;
1744
ret = sysdb_store_user_recv(subreq);
1746
tevent_req_error(req, ret);
1749
talloc_zfree(subreq);
1754
size = num*sizeof(gid_t);
1755
gids = talloc_size(state, size);
1757
tevent_req_error(req, ENOMEM);
1761
state->gid = state->pwd->pw_gid;
1764
/* FIXME: should we move this call outside the transaction to keep the
1765
* transaction as short as possible ? */
1766
status = ctx->ops.initgroups_dyn(state->name, state->gid, &num_gids,
1767
&num, &gids, limit, &ret);
1769
case NSS_STATUS_TRYAGAIN:
1770
/* buffer too small ? */
1771
if (size < MAX_BUF_SIZE) {
1773
size = num*sizeof(gid_t);
1775
if (size > MAX_BUF_SIZE) {
1776
size = MAX_BUF_SIZE;
1777
num = size/sizeof(gid_t);
1780
gids = talloc_realloc_size(state, gids, size);
1782
tevent_req_error(req, ENOMEM);
1785
goto again; /* retry with more memory */
1787
case NSS_STATUS_SUCCESS:
1788
DEBUG(4, ("User [%s] appears to be member of %lu groups\n",
1789
state->name, num_gids));
1791
subreq = get_groups_by_gid_send(state, state->ev, state->handle,
1792
state->ctx, state->domain,
1795
tevent_req_error(req, ENOMEM);
1798
tevent_req_set_callback(subreq, get_initgr_groups_done, req);
1802
DEBUG(2, ("proxy -> initgroups_dyn failed (%d)[%s]\n",
1803
ret, strerror(ret)));
1804
tevent_req_error(req, EIO);
1809
static void get_initgr_groups_done(struct tevent_req *subreq)
1811
struct tevent_req *req = tevent_req_callback_data(subreq,
1813
struct proxy_state *state = tevent_req_data(req,
1814
struct proxy_state);
1817
ret = get_groups_by_gid_recv(subreq);
1818
talloc_zfree(subreq);
1820
tevent_req_error(req, ret);
1824
subreq = sysdb_transaction_commit_send(state, state->ev, state->handle);
1826
tevent_req_error(req, ENOMEM);
1829
tevent_req_set_callback(subreq, proxy_default_done, req);
1832
struct get_groups_state {
1833
struct tevent_context *ev;
1834
struct sysdb_handle *handle;
1835
struct proxy_ctx *ctx;
1836
struct sss_domain_info *domain;
1843
static struct tevent_req *get_groups_by_gid_send(TALLOC_CTX *mem_ctx,
1844
struct tevent_context *ev,
1845
struct sysdb_handle *handle,
1846
struct proxy_ctx *ctx,
1847
struct sss_domain_info *domain,
1848
gid_t *gids, int num_gids)
1850
struct tevent_req *req, *subreq;
1851
struct get_groups_state *state;
1853
req = tevent_req_create(mem_ctx, &state, struct get_groups_state);
1854
if (!req) return NULL;
1857
state->handle = handle;
1859
state->domain = domain;
1861
state->num_gids = num_gids;
1864
subreq = get_group_from_gid_send(state, ev, handle, ctx, domain, gids[0]);
1869
tevent_req_set_callback(subreq, get_groups_by_gid_process, req);
1874
static void get_groups_by_gid_process(struct tevent_req *subreq)
1876
struct tevent_req *req = tevent_req_callback_data(subreq,
1878
struct get_groups_state *state = tevent_req_data(req,
1879
struct get_groups_state);
1882
ret = get_group_from_gid_recv(subreq);
1883
talloc_zfree(subreq);
1885
tevent_req_error(req, ret);
1890
if (state->cur_gid >= state->num_gids) {
1891
tevent_req_done(req);
1895
subreq = get_group_from_gid_send(state,
1896
state->ev, state->handle,
1897
state->ctx, state->domain,
1898
state->gids[state->cur_gid]);
1900
tevent_req_error(req, ENOMEM);
1903
tevent_req_set_callback(subreq, get_groups_by_gid_process, req);
1906
static int get_groups_by_gid_recv(struct tevent_req *req)
1908
TEVENT_REQ_RETURN_ON_ERROR(req);
1913
static struct tevent_req *get_group_from_gid_send(TALLOC_CTX *mem_ctx,
1914
struct tevent_context *ev,
1915
struct sysdb_handle *handle,
1916
struct proxy_ctx *ctx,
1917
struct sss_domain_info *domain,
1920
struct tevent_req *req, *subreq;
1921
struct proxy_state *state;
1922
struct sss_domain_info *dom = ctx->be->domain;
1923
enum nss_status status;
1927
bool delete_group = false;
1928
struct sysdb_attrs *members;
1931
req = tevent_req_create(mem_ctx, &state, struct proxy_state);
1932
if (!req) return NULL;
1934
memset(state, 0, sizeof(struct proxy_state));
1937
state->handle = handle;
1939
state->domain = domain;
1942
state->grp = talloc(state, struct group);
1948
buflen = DEFAULT_BUFSIZE;
1949
buffer = talloc_size(state, buflen);
1956
/* always zero out the grp structure */
1957
memset(state->grp, 0, sizeof(struct group));
1959
status = ctx->ops.getgrgid_r(state->gid, state->grp,
1960
buffer, buflen, &ret);
1963
case NSS_STATUS_TRYAGAIN:
1964
/* buffer too small ? */
1965
if (buflen < MAX_BUF_SIZE) {
1968
if (buflen > MAX_BUF_SIZE) {
1969
buflen = MAX_BUF_SIZE;
1971
newbuf = talloc_realloc_size(state, buffer, buflen);
1979
case NSS_STATUS_NOTFOUND:
1981
delete_group = true;
1984
case NSS_STATUS_SUCCESS:
1986
/* gid=0 is an invalid value */
1987
/* also check that the id is in the valid range for this domain */
1988
if (OUT_OF_ID_RANGE(state->grp->gr_gid, dom->id_min, dom->id_max)) {
1990
DEBUG(2, ("Group [%s] filtered out! (id out of range)\n",
1991
state->grp->gr_name));
1992
delete_group = true;
1996
if (state->grp->gr_mem && state->grp->gr_mem[0]) {
1997
members = sysdb_new_attrs(state);
2002
ret = sysdb_attrs_users_from_str_list(members, SYSDB_MEMBER,
2003
state->domain->name,
2004
(const char **)state->grp->gr_mem);
2012
subreq = sysdb_store_group_send(state, state->ev, state->handle,
2014
state->grp->gr_name,
2017
ctx->entry_cache_timeout);
2022
tevent_req_set_callback(subreq, get_group_from_gid_send_add_done, req);
2025
case NSS_STATUS_UNAVAIL:
2026
/* "remote" backend unavailable. Enter offline mode */
2031
DEBUG(2, ("proxy -> getgrgid_r failed for '%d' <%d>\n",
2032
state->gid, status));
2038
subreq = sysdb_delete_group_send(state, state->ev,
2039
NULL, state->handle,
2046
tevent_req_set_callback(subreq, get_group_from_gid_send_del_done, req);
2052
tevent_req_error(req, ret);
2053
tevent_req_post(req, ev);
2057
static void get_group_from_gid_send_add_done(struct tevent_req *subreq)
2059
struct tevent_req *req = tevent_req_callback_data(subreq,
2063
ret = sysdb_store_group_recv(subreq);
2064
talloc_zfree(subreq);
2066
tevent_req_error(req, ret);
2070
tevent_req_done(req);
2073
static void get_group_from_gid_send_del_done(struct tevent_req *subreq)
2075
struct tevent_req *req = tevent_req_callback_data(subreq,
2079
ret = sysdb_delete_entry_recv(subreq);
2080
talloc_zfree(subreq);
2081
if (ret && ret != ENOENT) {
2082
tevent_req_error(req, ret);
2086
tevent_req_done(req);
2089
static int get_group_from_gid_recv(struct tevent_req *req)
2091
TEVENT_REQ_RETURN_ON_ERROR(req);
2097
/* =Proxy_Id-Functions====================================================*/
2099
static void proxy_get_account_info_done(struct tevent_req *subreq);
2101
/* TODO: See if we can use async_req code */
2102
static void proxy_get_account_info(struct be_req *breq)
2104
struct tevent_req *subreq;
2105
struct be_acct_req *ar;
2106
struct proxy_ctx *ctx;
2107
struct tevent_context *ev;
2108
struct sysdb_ctx *sysdb;
2109
struct sss_domain_info *domain;
2113
ar = talloc_get_type(breq->req_data, struct be_acct_req);
2114
ctx = talloc_get_type(breq->be_ctx->bet_info[BET_ID].pvt_bet_data, struct proxy_ctx);
2115
ev = breq->be_ctx->ev;
2116
sysdb = breq->be_ctx->sysdb;
2117
domain = breq->be_ctx->domain;
2119
if (be_is_offline(breq->be_ctx)) {
2120
return proxy_reply(breq, DP_ERR_OFFLINE, EAGAIN, "Offline");
2123
/* for now we support only core attrs */
2124
if (ar->attr_type != BE_ATTR_CORE) {
2125
return proxy_reply(breq, DP_ERR_FATAL, EINVAL, "Invalid attr type");
2128
switch (ar->entry_type & 0xFFF) {
2129
case BE_REQ_USER: /* user */
2130
switch (ar->filter_type) {
2131
case BE_FILTER_NAME:
2132
if (strchr(ar->filter_value, '*')) {
2133
subreq = enum_users_send(breq, ev, ctx,
2136
return proxy_reply(breq, DP_ERR_FATAL,
2137
ENOMEM, "Out of memory");
2139
tevent_req_set_callback(subreq,
2140
proxy_get_account_info_done, breq);
2143
subreq = get_pw_name_send(breq, ev, ctx,
2147
return proxy_reply(breq, DP_ERR_FATAL,
2148
ENOMEM, "Out of memory");
2150
tevent_req_set_callback(subreq,
2151
proxy_get_account_info_done, breq);
2156
case BE_FILTER_IDNUM:
2157
if (strchr(ar->filter_value, '*')) {
2158
return proxy_reply(breq, DP_ERR_FATAL,
2159
EINVAL, "Invalid attr type");
2163
uid = (uid_t)strtol(ar->filter_value, &endptr, 0);
2164
if (errno || *endptr || (ar->filter_value == endptr)) {
2165
return proxy_reply(breq, DP_ERR_FATAL,
2166
EINVAL, "Invalid attr type");
2168
subreq = get_pw_uid_send(breq, ev, ctx,
2169
sysdb, domain, uid);
2171
return proxy_reply(breq, DP_ERR_FATAL,
2172
ENOMEM, "Out of memory");
2174
tevent_req_set_callback(subreq,
2175
proxy_get_account_info_done, breq);
2180
return proxy_reply(breq, DP_ERR_FATAL,
2181
EINVAL, "Invalid filter type");
2185
case BE_REQ_GROUP: /* group */
2186
switch (ar->filter_type) {
2187
case BE_FILTER_NAME:
2188
if (strchr(ar->filter_value, '*')) {
2189
subreq = enum_groups_send(breq, ev, ctx,
2192
return proxy_reply(breq, DP_ERR_FATAL,
2193
ENOMEM, "Out of memory");
2195
tevent_req_set_callback(subreq,
2196
proxy_get_account_info_done, breq);
2199
subreq = get_gr_name_send(breq, ev, ctx,
2203
return proxy_reply(breq, DP_ERR_FATAL,
2204
ENOMEM, "Out of memory");
2206
tevent_req_set_callback(subreq,
2207
proxy_get_account_info_done, breq);
2211
case BE_FILTER_IDNUM:
2212
if (strchr(ar->filter_value, '*')) {
2213
return proxy_reply(breq, DP_ERR_FATAL,
2214
EINVAL, "Invalid attr type");
2218
gid = (gid_t)strtol(ar->filter_value, &endptr, 0);
2219
if (errno || *endptr || (ar->filter_value == endptr)) {
2220
return proxy_reply(breq, DP_ERR_FATAL,
2221
EINVAL, "Invalid attr type");
2223
subreq = get_gr_gid_send(breq, ev, ctx,
2224
sysdb, domain, gid);
2226
return proxy_reply(breq, DP_ERR_FATAL,
2227
ENOMEM, "Out of memory");
2229
tevent_req_set_callback(subreq,
2230
proxy_get_account_info_done, breq);
2235
return proxy_reply(breq, DP_ERR_FATAL,
2236
EINVAL, "Invalid filter type");
2240
case BE_REQ_INITGROUPS: /* init groups for user */
2241
if (ar->filter_type != BE_FILTER_NAME) {
2242
return proxy_reply(breq, DP_ERR_FATAL,
2243
EINVAL, "Invalid filter type");
2245
if (strchr(ar->filter_value, '*')) {
2246
return proxy_reply(breq, DP_ERR_FATAL,
2247
EINVAL, "Invalid filter value");
2249
if (ctx->ops.initgroups_dyn == NULL) {
2250
return proxy_reply(breq, DP_ERR_FATAL,
2251
ENODEV, "Initgroups call not supported");
2253
subreq = get_initgr_send(breq, ev, ctx, sysdb,
2254
domain, ar->filter_value);
2256
return proxy_reply(breq, DP_ERR_FATAL,
2257
ENOMEM, "Out of memory");
2259
tevent_req_set_callback(subreq,
2260
proxy_get_account_info_done, breq);
2267
return proxy_reply(breq, DP_ERR_FATAL,
2268
EINVAL, "Invalid request type");
2271
static void proxy_get_account_info_done(struct tevent_req *subreq)
2273
struct be_req *breq = tevent_req_callback_data(subreq,
2276
ret = proxy_default_recv(subreq);
2277
talloc_zfree(subreq);
2280
DEBUG(2, ("proxy returned UNAVAIL error, going offline!\n"));
2281
be_mark_offline(breq->be_ctx);
2283
proxy_reply(breq, DP_ERR_FATAL, ret, NULL);
2286
proxy_reply(breq, DP_ERR_OK, EOK, NULL);
2289
static void proxy_shutdown(struct be_req *req)
2291
/* TODO: Clean up any internal data */
2292
req->fn(req, DP_ERR_OK, EOK, NULL);
2295
static void proxy_auth_shutdown(struct be_req *req)
2297
talloc_free(req->be_ctx->bet_info[BET_AUTH].pvt_bet_data);
2298
req->fn(req, DP_ERR_OK, EOK, NULL);
2301
struct bet_ops proxy_id_ops = {
2302
.handler = proxy_get_account_info,
2303
.finalize = proxy_shutdown
2306
struct bet_ops proxy_auth_ops = {
2307
.handler = proxy_pam_handler,
2308
.finalize = proxy_auth_shutdown
2311
struct bet_ops proxy_access_ops = {
2312
.handler = proxy_pam_handler,
2313
.finalize = proxy_auth_shutdown
2316
struct bet_ops proxy_chpass_ops = {
2317
.handler = proxy_pam_handler,
2318
.finalize = proxy_auth_shutdown
2321
static void *proxy_dlsym(void *handle, const char *functemp, char *libname)
2326
funcname = talloc_asprintf(NULL, functemp, libname);
2327
if (funcname == NULL) return NULL;
2329
funcptr = dlsym(handle, funcname);
2330
talloc_free(funcname);
2335
int sssm_proxy_init(struct be_ctx *bectx,
2336
struct bet_ops **ops, void **pvt_data)
2338
struct proxy_ctx *ctx;
2344
ctx = talloc_zero(bectx, struct proxy_ctx);
2350
ret = confdb_get_int(bectx->cdb, ctx, bectx->conf_path,
2351
CONFDB_DOMAIN_ENTRY_CACHE_TIMEOUT, 600,
2352
&ctx->entry_cache_timeout);
2353
if (ret != EOK) goto done;
2355
ret = confdb_get_string(bectx->cdb, ctx, bectx->conf_path,
2356
CONFDB_PROXY_LIBNAME, NULL, &libname);
2357
if (ret != EOK) goto done;
2358
if (libname == NULL) {
2363
libpath = talloc_asprintf(ctx, "libnss_%s.so.2", libname);
2369
handle = dlopen(libpath, RTLD_NOW);
2371
DEBUG(0, ("Unable to load %s module with path, error: %s\n",
2372
libpath, dlerror()));
2377
ctx->ops.getpwnam_r = proxy_dlsym(handle, "_nss_%s_getpwnam_r", libname);
2378
if (!ctx->ops.getpwnam_r) {
2379
DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror()));
2384
ctx->ops.getpwuid_r = proxy_dlsym(handle, "_nss_%s_getpwuid_r", libname);
2385
if (!ctx->ops.getpwuid_r) {
2386
DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror()));
2391
ctx->ops.setpwent = proxy_dlsym(handle, "_nss_%s_setpwent", libname);
2392
if (!ctx->ops.setpwent) {
2393
DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror()));
2398
ctx->ops.getpwent_r = proxy_dlsym(handle, "_nss_%s_getpwent_r", libname);
2399
if (!ctx->ops.getpwent_r) {
2400
DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror()));
2405
ctx->ops.endpwent = proxy_dlsym(handle, "_nss_%s_endpwent", libname);
2406
if (!ctx->ops.endpwent) {
2407
DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror()));
2412
ctx->ops.getgrnam_r = proxy_dlsym(handle, "_nss_%s_getgrnam_r", libname);
2413
if (!ctx->ops.getgrnam_r) {
2414
DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror()));
2419
ctx->ops.getgrgid_r = proxy_dlsym(handle, "_nss_%s_getgrgid_r", libname);
2420
if (!ctx->ops.getgrgid_r) {
2421
DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror()));
2426
ctx->ops.setgrent = proxy_dlsym(handle, "_nss_%s_setgrent", libname);
2427
if (!ctx->ops.setgrent) {
2428
DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror()));
2433
ctx->ops.getgrent_r = proxy_dlsym(handle, "_nss_%s_getgrent_r", libname);
2434
if (!ctx->ops.getgrent_r) {
2435
DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror()));
2440
ctx->ops.endgrent = proxy_dlsym(handle, "_nss_%s_endgrent", libname);
2441
if (!ctx->ops.endgrent) {
2442
DEBUG(0, ("Failed to load NSS fns, error: %s\n", dlerror()));
2447
ctx->ops.initgroups_dyn = proxy_dlsym(handle, "_nss_%s_initgroups_dyn",
2449
if (!ctx->ops.initgroups_dyn) {
2450
DEBUG(1, ("The '%s' library does not provides the "
2451
"_nss_XXX_initgroups_dyn function!\n"
2452
"initgroups will be slow as it will require "
2453
"full groups enumeration!\n", libname));
2456
*ops = &proxy_id_ops;
2467
int sssm_proxy_auth_init(struct be_ctx *bectx,
2468
struct bet_ops **ops, void **pvt_data)
2470
struct proxy_auth_ctx *ctx;
2473
ctx = talloc(bectx, struct proxy_auth_ctx);
2479
ret = confdb_get_string(bectx->cdb, ctx, bectx->conf_path,
2480
CONFDB_PROXY_PAM_TARGET, NULL,
2482
if (ret != EOK) goto done;
2483
if (!ctx->pam_target) {
2484
DEBUG(1, ("Missing option proxy_pam_target.\n"));
2489
*ops = &proxy_auth_ops;
2499
int sssm_proxy_access_init(struct be_ctx *bectx,
2500
struct bet_ops **ops, void **pvt_data)
2503
ret = sssm_proxy_auth_init(bectx, ops, pvt_data);
2504
*ops = &proxy_access_ops;
2508
int sssm_proxy_chpass_init(struct be_ctx *bectx,
2509
struct bet_ops **ops, void **pvt_data)
2512
ret = sssm_proxy_auth_init(bectx, ops, pvt_data);
2513
*ops = &proxy_chpass_ops;