Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : async implementation of WINBINDD_PAM_LOGOFF
4 : Copyright (C) Volker Lendecke 2010
5 :
6 : This program is free software; you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation; either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include "includes.h"
21 : #include "util/debug.h"
22 : #include "winbindd.h"
23 : #include "lib/global_contexts.h"
24 : #include "librpc/gen_ndr/ndr_winbind_c.h"
25 : #include "lib/util/string_wrappers.h"
26 :
27 : struct winbindd_pam_logoff_state {
28 : struct wbint_PamLogOff r;
29 : };
30 :
31 : static void winbindd_pam_logoff_done(struct tevent_req *subreq);
32 :
33 20 : struct tevent_req *winbindd_pam_logoff_send(TALLOC_CTX *mem_ctx,
34 : struct tevent_context *ev,
35 : struct winbindd_cli_state *cli,
36 : struct winbindd_request *request)
37 : {
38 0 : struct tevent_req *req, *subreq;
39 0 : struct winbindd_pam_logoff_state *state;
40 0 : struct winbindd_domain *domain;
41 20 : char *name_namespace = NULL;
42 20 : char *name_domain = NULL;
43 20 : char *user = NULL;
44 20 : char *logoff_user = NULL;
45 :
46 0 : uid_t caller_uid;
47 0 : gid_t caller_gid;
48 0 : int res;
49 0 : bool ok;
50 :
51 20 : req = tevent_req_create(mem_ctx, &state,
52 : struct winbindd_pam_logoff_state);
53 20 : if (req == NULL) {
54 0 : return NULL;
55 : }
56 20 : D_NOTICE("[%s (%u)] Winbind external command PAM_LOGOFF start.\n"
57 : "Username '%s' is used during logoff.\n",
58 : cli->client_name,
59 : (unsigned int)cli->pid,
60 : request->data.auth.user);
61 : /* Ensure null termination */
62 : /* Ensure null termination */
63 20 : request->data.logoff.user[sizeof(request->data.logoff.user)-1]='\0';
64 0 : request->data.logoff.krb5ccname[
65 20 : sizeof(request->data.logoff.krb5ccname)-1]='\0';
66 :
67 20 : if (request->data.logoff.uid == (uid_t)-1) {
68 0 : goto failed;
69 : }
70 :
71 20 : logoff_user = request->data.logoff.user;
72 :
73 20 : ok = canonicalize_username(req,
74 : &logoff_user,
75 : &name_namespace,
76 : &name_domain,
77 : &user);
78 20 : if (!ok) {
79 0 : goto failed;
80 : }
81 :
82 20 : fstrcpy(request->data.logoff.user, logoff_user);
83 :
84 20 : domain = find_auth_domain(request->flags, name_namespace);
85 20 : if (domain == NULL) {
86 0 : goto failed;
87 : }
88 :
89 20 : caller_uid = (uid_t)-1;
90 :
91 20 : res = getpeereid(cli->sock, &caller_uid, &caller_gid);
92 20 : if (res != 0) {
93 0 : D_WARNING("winbindd_pam_logoff: failed to check peerid: %s\n",
94 : strerror(errno));
95 0 : goto failed;
96 : }
97 :
98 20 : switch (caller_uid) {
99 0 : case -1:
100 0 : goto failed;
101 0 : case 0:
102 : /* root must be able to logoff any user - gd */
103 0 : break;
104 20 : default:
105 20 : if (caller_uid != request->data.logoff.uid) {
106 0 : D_WARNING("caller requested invalid uid\n");
107 0 : goto failed;
108 : }
109 20 : break;
110 : }
111 :
112 20 : state->r.in.client_name = talloc_strdup(state, request->client_name);
113 20 : if (tevent_req_nomem(state->r.in.client_name, req)) {
114 0 : return tevent_req_post(req, ev);
115 : }
116 20 : state->r.in.client_pid = request->pid;
117 :
118 20 : state->r.in.flags = request->flags;
119 20 : state->r.in.user = talloc_strdup(state, request->data.logoff.user);
120 20 : if (tevent_req_nomem(state->r.in.user, req)) {
121 0 : return tevent_req_post(req, ev);
122 : }
123 20 : state->r.in.uid = request->data.logoff.uid;
124 40 : state->r.in.krb5ccname = talloc_strdup(state,
125 20 : request->data.logoff.krb5ccname);
126 20 : if (tevent_req_nomem(state->r.in.krb5ccname, req)) {
127 0 : return tevent_req_post(req, ev);
128 : }
129 :
130 20 : subreq = dcerpc_wbint_PamLogOff_r_send(state,
131 : global_event_context(),
132 : dom_child_handle(domain),
133 20 : &state->r);
134 20 : if (tevent_req_nomem(subreq, req)) {
135 0 : return tevent_req_post(req, ev);
136 : }
137 20 : tevent_req_set_callback(subreq, winbindd_pam_logoff_done, req);
138 20 : return req;
139 :
140 0 : failed:
141 0 : tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
142 0 : return tevent_req_post(req, ev);
143 : }
144 :
145 20 : static void winbindd_pam_logoff_done(struct tevent_req *subreq)
146 : {
147 20 : struct tevent_req *req = tevent_req_callback_data(
148 : subreq, struct tevent_req);
149 20 : struct winbindd_pam_logoff_state *state = tevent_req_data(
150 : req, struct winbindd_pam_logoff_state);
151 0 : NTSTATUS status;
152 :
153 20 : status = dcerpc_wbint_PamLogOff_r_recv(subreq, state);
154 20 : TALLOC_FREE(subreq);
155 20 : if (tevent_req_nterror(req, status)) {
156 0 : return;
157 : }
158 :
159 20 : tevent_req_done(req);
160 : }
161 :
162 20 : NTSTATUS winbindd_pam_logoff_recv(struct tevent_req *req,
163 : struct winbindd_response *response)
164 : {
165 20 : struct winbindd_pam_logoff_state *state = tevent_req_data(
166 : req, struct winbindd_pam_logoff_state);
167 20 : NTSTATUS status = NT_STATUS_OK;
168 :
169 20 : D_NOTICE("Winbind external command PAM_LOGOFF end.\n");
170 20 : if (tevent_req_is_nterror(req, &status)) {
171 0 : set_auth_errors(response, status);
172 0 : return status;
173 : }
174 :
175 20 : response->result = WINBINDD_PENDING;
176 20 : set_auth_errors(response, state->r.out.result);
177 :
178 20 : if (NT_STATUS_IS_OK(state->r.out.result)) {
179 20 : winbindd_delete_memory_creds(state->r.in.user);
180 : }
181 :
182 20 : return NT_STATUS(response->data.auth.nt_status);
183 : }
|