Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : winbind client common code
5 :
6 : Copyright (C) Tim Potter 2000
7 : Copyright (C) Andrew Tridgell 2000
8 : Copyright (C) Andrew Bartlett 2002
9 : Copyright (C) Matthew Newton 2015
10 :
11 :
12 : This library is free software; you can redistribute it and/or
13 : modify it under the terms of the GNU Lesser General Public
14 : License as published by the Free Software Foundation; either
15 : version 3 of the License, or (at your option) any later version.
16 :
17 : This library is distributed in the hope that it will be useful,
18 : but WITHOUT ANY WARRANTY; without even the implied warranty of
19 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 : Library General Public License for more details.
21 :
22 : You should have received a copy of the GNU Lesser General Public License
23 : along with this program. If not, see <http://www.gnu.org/licenses/>.
24 : */
25 :
26 : #include "replace.h"
27 : #include "system/select.h"
28 : #include "winbind_client.h"
29 :
30 : #ifdef HAVE_PTHREAD_H
31 : #include <pthread.h>
32 : #endif
33 :
34 : static char client_name[32];
35 :
36 : /* Global context */
37 :
38 : struct winbindd_context {
39 : int winbindd_fd; /* winbind file descriptor */
40 : bool is_privileged; /* using the privileged socket? */
41 : pid_t our_pid; /* calling process pid */
42 : };
43 :
44 : #ifdef HAVE_PTHREAD
45 : static pthread_mutex_t wb_global_ctx_mutex = PTHREAD_MUTEX_INITIALIZER;
46 : #endif
47 :
48 605067 : static struct winbindd_context *get_wb_global_ctx(void)
49 : {
50 : static struct winbindd_context wb_global_ctx = {
51 : .winbindd_fd = -1,
52 : .is_privileged = false,
53 : .our_pid = 0
54 : };
55 :
56 : #ifdef HAVE_PTHREAD
57 607739 : pthread_mutex_lock(&wb_global_ctx_mutex);
58 : #endif
59 605067 : return &wb_global_ctx;
60 : }
61 :
62 605067 : static void put_wb_global_ctx(void)
63 : {
64 : #ifdef HAVE_PTHREAD
65 607739 : pthread_mutex_unlock(&wb_global_ctx_mutex);
66 : #endif
67 605067 : return;
68 : }
69 :
70 : /* Free a response structure */
71 :
72 189763 : void winbindd_free_response(struct winbindd_response *response)
73 : {
74 : /* Free any allocated extra_data */
75 :
76 189763 : if (response)
77 189763 : SAFE_FREE(response->extra_data.data);
78 189763 : }
79 :
80 106590 : void winbind_set_client_name(const char *name)
81 : {
82 106590 : if (name == NULL || strlen(name) == 0) {
83 0 : return;
84 : }
85 :
86 106042 : (void)snprintf(client_name, sizeof(client_name), "%s", name);
87 : }
88 :
89 464079 : static const char *winbind_get_client_name(void)
90 : {
91 464079 : if (client_name[0] == '\0') {
92 2656 : const char *progname = getprogname();
93 : int len;
94 :
95 2656 : if (progname == NULL) {
96 0 : progname = "<unknown>";
97 : }
98 :
99 2656 : len = snprintf(client_name,
100 : sizeof(client_name),
101 : "%s",
102 : progname);
103 2656 : if (len <= 0) {
104 0 : return progname;
105 : }
106 : }
107 :
108 462416 : return client_name;
109 : }
110 :
111 : /* Initialise a request structure */
112 :
113 464079 : static void winbindd_init_request(struct winbindd_request *request,
114 : int request_type)
115 : {
116 464079 : request->length = sizeof(struct winbindd_request);
117 :
118 464079 : request->cmd = (enum winbindd_cmd)request_type;
119 464079 : request->pid = getpid();
120 :
121 465742 : (void)snprintf(request->client_name,
122 : sizeof(request->client_name),
123 : "%s",
124 : winbind_get_client_name());
125 464079 : }
126 :
127 : /* Initialise a response structure */
128 :
129 254067 : static void init_response(struct winbindd_response *response)
130 : {
131 : /* Initialise return value */
132 :
133 255645 : response->result = WINBINDD_ERROR;
134 254067 : }
135 :
136 : /* Close established socket */
137 :
138 103950 : static void winbind_close_sock(struct winbindd_context *ctx)
139 : {
140 103950 : if (!ctx) {
141 0 : return;
142 : }
143 :
144 105997 : if (ctx->winbindd_fd != -1) {
145 24600 : close(ctx->winbindd_fd);
146 24600 : ctx->winbindd_fd = -1;
147 : }
148 : }
149 :
150 : /* Destructor for global context to ensure fd is closed */
151 :
152 : #ifdef HAVE_DESTRUCTOR_ATTRIBUTE
153 : __attribute__((destructor))
154 : #elif defined (HAVE_PRAGMA_FINI)
155 : #pragma fini (winbind_destructor)
156 : #endif
157 82634 : static void winbind_destructor(void)
158 : {
159 : struct winbindd_context *ctx;
160 :
161 82634 : ctx = get_wb_global_ctx();
162 82634 : winbind_close_sock(ctx);
163 81123 : put_wb_global_ctx();
164 82634 : }
165 :
166 : #define CONNECT_TIMEOUT 30
167 :
168 : /* Make sure socket handle isn't stdin, stdout or stderr */
169 : #define RECURSION_LIMIT 3
170 :
171 14011 : static int make_nonstd_fd_internals(int fd, int limit /* Recursion limiter */)
172 : {
173 : int new_fd;
174 14011 : if (fd >= 0 && fd <= 2) {
175 : #ifdef F_DUPFD
176 0 : if ((new_fd = fcntl(fd, F_DUPFD, 3)) == -1) {
177 0 : return -1;
178 : }
179 : /* Paranoia */
180 0 : if (new_fd < 3) {
181 0 : close(new_fd);
182 0 : return -1;
183 : }
184 0 : close(fd);
185 0 : return new_fd;
186 : #else
187 : if (limit <= 0)
188 : return -1;
189 :
190 : new_fd = dup(fd);
191 : if (new_fd == -1)
192 : return -1;
193 :
194 : /* use the program stack to hold our list of FDs to close */
195 : new_fd = make_nonstd_fd_internals(new_fd, limit - 1);
196 : close(fd);
197 : return new_fd;
198 : #endif
199 : }
200 13487 : return fd;
201 : }
202 :
203 : /****************************************************************************
204 : Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
205 : else
206 : if SYSV use O_NDELAY
207 : if BSD use FNDELAY
208 : Set close on exec also.
209 : ****************************************************************************/
210 :
211 14011 : static int make_safe_fd(int fd)
212 : {
213 : int result, flags;
214 14011 : int new_fd = make_nonstd_fd_internals(fd, RECURSION_LIMIT);
215 14011 : if (new_fd == -1) {
216 0 : close(fd);
217 0 : return -1;
218 : }
219 :
220 : /* Socket should be nonblocking. */
221 : #ifdef O_NONBLOCK
222 : #define FLAG_TO_SET O_NONBLOCK
223 : #else
224 : #ifdef SYSV
225 : #define FLAG_TO_SET O_NDELAY
226 : #else /* BSD */
227 : #define FLAG_TO_SET FNDELAY
228 : #endif
229 : #endif
230 :
231 14011 : if ((flags = fcntl(new_fd, F_GETFL)) == -1) {
232 0 : close(new_fd);
233 0 : return -1;
234 : }
235 :
236 14011 : flags |= FLAG_TO_SET;
237 14011 : if (fcntl(new_fd, F_SETFL, flags) == -1) {
238 0 : close(new_fd);
239 0 : return -1;
240 : }
241 :
242 : #undef FLAG_TO_SET
243 :
244 : /* Socket should be closed on exec() */
245 : #ifdef FD_CLOEXEC
246 14011 : result = flags = fcntl(new_fd, F_GETFD, 0);
247 14011 : if (flags >= 0) {
248 14011 : flags |= FD_CLOEXEC;
249 14011 : result = fcntl( new_fd, F_SETFD, flags );
250 : }
251 14011 : if (result < 0) {
252 0 : close(new_fd);
253 0 : return -1;
254 : }
255 : #endif
256 13487 : return new_fd;
257 : }
258 :
259 : /**
260 : * @internal
261 : *
262 : * @brief Check if we talk to the privileged pipe which should be owned by root.
263 : *
264 : * This checks if we have uid_wrapper running and if this is the case it will
265 : * allow one to connect to the winbind privileged pipe even it is not owned by root.
266 : *
267 : * @param[in] uid The uid to check if we can safely talk to the pipe.
268 : *
269 : * @return If we have access it returns true, else false.
270 : */
271 26978 : static bool winbind_privileged_pipe_is_root(uid_t uid)
272 : {
273 28026 : if (uid == 0) {
274 0 : return true;
275 : }
276 :
277 28026 : if (uid_wrapper_enabled()) {
278 26978 : return true;
279 : }
280 :
281 0 : return false;
282 : }
283 :
284 : /* Connect to winbindd socket */
285 :
286 222445 : static int winbind_named_pipe_sock(const char *dir)
287 : {
288 : struct sockaddr_un sunaddr;
289 : struct stat st;
290 : int fd;
291 : int wait_time;
292 : int slept;
293 : int ret;
294 :
295 : /* Check permissions on unix socket directory */
296 :
297 222445 : if (lstat(dir, &st) == -1) {
298 208430 : errno = ENOENT;
299 208430 : return -1;
300 : }
301 :
302 : /*
303 : * This tells us that the pipe is owned by a privileged
304 : * process, as we will be sending passwords to it.
305 : */
306 23039 : if (!S_ISDIR(st.st_mode) ||
307 14015 : !winbind_privileged_pipe_is_root(st.st_uid)) {
308 0 : errno = ENOENT;
309 0 : return -1;
310 : }
311 :
312 : /* Connect to socket */
313 :
314 14015 : sunaddr = (struct sockaddr_un) { .sun_family = AF_UNIX };
315 :
316 14015 : ret = snprintf(sunaddr.sun_path, sizeof(sunaddr.sun_path),
317 : "%s/%s", dir, WINBINDD_SOCKET_NAME);
318 14015 : if ((ret == -1) || (ret >= sizeof(sunaddr.sun_path))) {
319 0 : errno = ENAMETOOLONG;
320 0 : return -1;
321 : }
322 :
323 : /* If socket file doesn't exist, don't bother trying to connect
324 : with retry. This is an attempt to make the system usable when
325 : the winbindd daemon is not running. */
326 :
327 14015 : if (lstat(sunaddr.sun_path, &st) == -1) {
328 4 : errno = ENOENT;
329 4 : return -1;
330 : }
331 :
332 : /* Check permissions on unix socket file */
333 :
334 : /*
335 : * This tells us that the pipe is owned by a privileged
336 : * process, as we will be sending passwords to it.
337 : */
338 23033 : if (!S_ISSOCK(st.st_mode) ||
339 14011 : !winbind_privileged_pipe_is_root(st.st_uid)) {
340 0 : errno = ENOENT;
341 0 : return -1;
342 : }
343 :
344 : /* Connect to socket */
345 :
346 14011 : if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
347 0 : return -1;
348 : }
349 :
350 : /* Set socket non-blocking and close on exec. */
351 :
352 14011 : if ((fd = make_safe_fd( fd)) == -1) {
353 0 : return fd;
354 : }
355 :
356 23033 : for (wait_time = 0; connect(fd, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1;
357 0 : wait_time += slept) {
358 : struct pollfd pfd;
359 0 : int connect_errno = 0;
360 : socklen_t errnosize;
361 :
362 0 : if (wait_time >= CONNECT_TIMEOUT)
363 0 : goto error_out;
364 :
365 0 : switch (errno) {
366 0 : case EINPROGRESS:
367 0 : pfd.fd = fd;
368 0 : pfd.events = POLLOUT;
369 :
370 0 : ret = poll(&pfd, 1, (CONNECT_TIMEOUT - wait_time) * 1000);
371 :
372 0 : if (ret > 0) {
373 0 : errnosize = sizeof(connect_errno);
374 :
375 0 : ret = getsockopt(fd, SOL_SOCKET,
376 : SO_ERROR, &connect_errno, &errnosize);
377 :
378 0 : if (ret >= 0 && connect_errno == 0) {
379 : /* Connect succeed */
380 0 : goto out;
381 : }
382 : }
383 :
384 0 : slept = CONNECT_TIMEOUT;
385 0 : break;
386 0 : case EAGAIN:
387 0 : slept = rand() % 3 + 1;
388 0 : sleep(slept);
389 0 : break;
390 0 : default:
391 0 : goto error_out;
392 : }
393 :
394 : }
395 :
396 14011 : out:
397 :
398 13487 : return fd;
399 :
400 0 : error_out:
401 :
402 0 : close(fd);
403 0 : return -1;
404 : }
405 :
406 221425 : static const char *winbindd_socket_dir(void)
407 : {
408 221425 : if (nss_wrapper_enabled()) {
409 : const char *env_dir;
410 :
411 221280 : env_dir = getenv("SELFTEST_WINBINDD_SOCKET_DIR");
412 221280 : if (env_dir != NULL) {
413 219728 : return env_dir;
414 : }
415 : }
416 :
417 1088 : return WINBINDD_SOCKET_DIR;
418 : }
419 :
420 : /* Connect to winbindd socket */
421 :
422 802305 : static int winbind_open_pipe_sock(struct winbindd_context *ctx,
423 : int recursing, int need_priv)
424 : {
425 : #ifdef HAVE_UNIXSOCKET
426 : struct winbindd_request request;
427 : struct winbindd_response response;
428 :
429 802305 : ZERO_STRUCT(request);
430 802305 : ZERO_STRUCT(response);
431 :
432 802305 : if (!ctx) {
433 0 : return -1;
434 : }
435 :
436 802305 : if (ctx->our_pid != getpid()) {
437 22437 : winbind_close_sock(ctx);
438 22437 : ctx->our_pid = getpid();
439 : }
440 :
441 802305 : if ((need_priv != 0) && !ctx->is_privileged) {
442 635 : winbind_close_sock(ctx);
443 : }
444 :
445 802305 : if (ctx->winbindd_fd != -1) {
446 577202 : return ctx->winbindd_fd;
447 : }
448 :
449 221425 : if (recursing) {
450 0 : return -1;
451 : }
452 :
453 221425 : ctx->winbindd_fd = winbind_named_pipe_sock(winbindd_socket_dir());
454 :
455 221425 : if (ctx->winbindd_fd == -1) {
456 208349 : return -1;
457 : }
458 :
459 12991 : ctx->is_privileged = false;
460 :
461 : /* version-check the socket */
462 :
463 12991 : request.wb_flags = WBFLAG_RECURSE;
464 12991 : if ((winbindd_request_response(ctx, WINBINDD_INTERFACE_VERSION, &request,
465 12991 : &response) != NSS_STATUS_SUCCESS) ||
466 12991 : (response.data.interface_version != WINBIND_INTERFACE_VERSION)) {
467 0 : winbind_close_sock(ctx);
468 0 : return -1;
469 : }
470 :
471 12991 : if (need_priv == 0) {
472 11971 : return ctx->winbindd_fd;
473 : }
474 :
475 : /* try and get priv pipe */
476 :
477 1020 : request.wb_flags = WBFLAG_RECURSE;
478 :
479 : /* Note that response needs to be initialized to avoid
480 : * crashing on clean up after WINBINDD_PRIV_PIPE_DIR call failed
481 : * as interface version (from the first request) returned as a fstring,
482 : * thus response.extra_data.data will not be NULL even though
483 : * winbindd response did not write over it due to a failure */
484 1020 : ZERO_STRUCT(response);
485 1020 : if (winbindd_request_response(ctx, WINBINDD_PRIV_PIPE_DIR, &request,
486 : &response) == NSS_STATUS_SUCCESS) {
487 : int fd;
488 1020 : fd = winbind_named_pipe_sock((char *)response.extra_data.data);
489 1020 : if (fd != -1) {
490 1020 : close(ctx->winbindd_fd);
491 1020 : ctx->winbindd_fd = fd;
492 1020 : ctx->is_privileged = true;
493 : }
494 :
495 1020 : SAFE_FREE(response.extra_data.data);
496 : }
497 :
498 1020 : if (!ctx->is_privileged) {
499 0 : return -1;
500 : }
501 :
502 1020 : return ctx->winbindd_fd;
503 : #else
504 : return -1;
505 : #endif /* HAVE_UNIXSOCKET */
506 : }
507 :
508 : /* Write data to winbindd socket */
509 :
510 503918 : static int winbind_write_sock(struct winbindd_context *ctx, void *buffer,
511 : int count, int recursing, int need_priv)
512 : {
513 : int fd, result, nwritten;
514 :
515 : /* Open connection to winbind daemon */
516 :
517 503918 : restart:
518 :
519 503918 : fd = winbind_open_pipe_sock(ctx, recursing, need_priv);
520 503918 : if (fd == -1) {
521 208434 : errno = ENOENT;
522 208434 : return -1;
523 : }
524 :
525 : /* Write data to socket */
526 :
527 293384 : nwritten = 0;
528 :
529 800152 : while(nwritten < count) {
530 : struct pollfd pfd;
531 : int ret;
532 :
533 : /* Catch pipe close on other end by checking if a read()
534 : call would not block by calling poll(). */
535 :
536 295484 : pfd.fd = fd;
537 295484 : pfd.events = POLLIN|POLLOUT|POLLHUP;
538 :
539 295484 : ret = poll(&pfd, 1, -1);
540 295484 : if (ret == -1) {
541 0 : winbind_close_sock(ctx);
542 0 : return -1; /* poll error */
543 : }
544 :
545 : /* Write should be OK if fd not available for reading */
546 :
547 295484 : if ((ret == 1) && (pfd.revents & (POLLIN|POLLHUP|POLLERR))) {
548 :
549 : /* Pipe has closed on remote end */
550 :
551 31 : winbind_close_sock(ctx);
552 31 : goto restart;
553 : }
554 :
555 : /* Do the write */
556 :
557 379622 : result = write(fd, (char *)buffer + nwritten,
558 295453 : count - nwritten);
559 :
560 295453 : if ((result == -1) || (result == 0)) {
561 :
562 : /* Write failed */
563 :
564 0 : winbind_close_sock(ctx);
565 0 : return -1;
566 : }
567 :
568 295453 : nwritten += result;
569 : }
570 :
571 293353 : return nwritten;
572 : }
573 :
574 : /* Read data from winbindd socket */
575 :
576 298387 : static int winbind_read_sock(struct winbindd_context *ctx,
577 : void *buffer, int count)
578 : {
579 : int fd;
580 298387 : int nread = 0;
581 298387 : int total_time = 0;
582 :
583 298387 : fd = winbind_open_pipe_sock(ctx, false, false);
584 298387 : if (fd == -1) {
585 0 : return -1;
586 : }
587 :
588 : /* Read data from socket */
589 807993 : while(nread < count) {
590 : struct pollfd pfd;
591 : int ret;
592 :
593 : /* Catch pipe close on other end by checking if a read()
594 : call would not block by calling poll(). */
595 :
596 298391 : pfd.fd = fd;
597 298391 : pfd.events = POLLIN|POLLHUP;
598 :
599 : /* Wait for 5 seconds for a reply. May need to parameterise this... */
600 :
601 298391 : ret = poll(&pfd, 1, 5000);
602 298391 : if (ret == -1) {
603 0 : winbind_close_sock(ctx);
604 0 : return -1; /* poll error */
605 : }
606 :
607 298391 : if (ret == 0) {
608 : /* Not ready for read yet... */
609 4 : if (total_time >= 300) {
610 : /* Timeout */
611 0 : winbind_close_sock(ctx);
612 0 : return -1;
613 : }
614 4 : total_time += 5;
615 4 : continue;
616 : }
617 :
618 298387 : if ((ret == 1) && (pfd.revents & (POLLIN|POLLHUP|POLLERR))) {
619 :
620 : /* Do the Read */
621 :
622 385559 : int result = read(fd, (char *)buffer + nread,
623 298387 : count - nread);
624 :
625 298387 : if ((result == -1) || (result == 0)) {
626 :
627 : /* Read failed. I think the only useful thing we
628 : can do here is just return -1 and fail since the
629 : transaction has failed half way through. */
630 :
631 0 : winbind_close_sock(ctx);
632 0 : return -1;
633 : }
634 :
635 298387 : nread += result;
636 :
637 : }
638 : }
639 :
640 296285 : return nread;
641 : }
642 :
643 : /* Read reply */
644 :
645 255645 : static int winbindd_read_reply(struct winbindd_context *ctx,
646 : struct winbindd_response *response)
647 : {
648 255645 : int result1, result2 = 0;
649 :
650 255645 : if (!response) {
651 0 : return -1;
652 : }
653 :
654 : /* Read fixed length response */
655 :
656 255645 : result1 = winbind_read_sock(ctx, response,
657 : sizeof(struct winbindd_response));
658 :
659 : /* We actually send the pointer value of the extra_data field from
660 : the server. This has no meaning in the client's address space
661 : so we clear it out. */
662 :
663 255645 : response->extra_data.data = NULL;
664 :
665 255645 : if (result1 == -1) {
666 0 : return -1;
667 : }
668 :
669 255645 : if (response->length < sizeof(struct winbindd_response)) {
670 0 : return -1;
671 : }
672 :
673 : /* Read variable length response */
674 :
675 255645 : if (response->length > sizeof(struct winbindd_response)) {
676 42742 : int extra_data_len = response->length -
677 : sizeof(struct winbindd_response);
678 :
679 : /* Mallocate memory for extra data */
680 :
681 42742 : if (!(response->extra_data.data = malloc(extra_data_len))) {
682 0 : return -1;
683 : }
684 :
685 42742 : result2 = winbind_read_sock(ctx, response->extra_data.data,
686 : extra_data_len);
687 42742 : if (result2 == -1) {
688 0 : winbindd_free_response(response);
689 0 : return -1;
690 : }
691 : }
692 :
693 : /* Return total amount of data read */
694 :
695 255645 : return result1 + result2;
696 : }
697 :
698 : /*
699 : * send simple types of requests
700 : */
701 :
702 540336 : static NSS_STATUS winbindd_send_request(
703 : struct winbindd_context *ctx,
704 : int req_type,
705 : int need_priv,
706 : struct winbindd_request *request)
707 : {
708 : struct winbindd_request lrequest;
709 :
710 : /* Check for our tricky environment variable */
711 :
712 540336 : if (winbind_env_set()) {
713 76235 : return NSS_STATUS_NOTFOUND;
714 : }
715 :
716 464079 : if (!request) {
717 128814 : ZERO_STRUCT(lrequest);
718 128814 : request = &lrequest;
719 : }
720 :
721 : /* Fill in request and send down pipe */
722 :
723 464079 : winbindd_init_request(request, req_type);
724 :
725 464079 : if (winbind_write_sock(ctx, request, sizeof(*request),
726 464079 : request->wb_flags & WBFLAG_RECURSE,
727 : need_priv) == -1)
728 : {
729 : /* Set ENOENT for consistency. Required by some apps */
730 208434 : errno = ENOENT;
731 :
732 208434 : return NSS_STATUS_UNAVAIL;
733 : }
734 :
735 295453 : if ((request->extra_len != 0) &&
736 69296 : (winbind_write_sock(ctx, request->extra_data.data,
737 39286 : request->extra_len,
738 39808 : request->wb_flags & WBFLAG_RECURSE,
739 : need_priv) == -1))
740 : {
741 : /* Set ENOENT for consistency. Required by some apps */
742 0 : errno = ENOENT;
743 :
744 0 : return NSS_STATUS_UNAVAIL;
745 : }
746 :
747 254067 : return NSS_STATUS_SUCCESS;
748 : }
749 :
750 : /*
751 : * Get results from winbindd request
752 : */
753 :
754 255645 : static NSS_STATUS winbindd_get_response(struct winbindd_context *ctx,
755 : struct winbindd_response *response)
756 : {
757 : struct winbindd_response lresponse;
758 :
759 255645 : if (!response) {
760 119962 : ZERO_STRUCT(lresponse);
761 119962 : response = &lresponse;
762 : }
763 :
764 255645 : init_response(response);
765 :
766 : /* Wait for reply */
767 255645 : if (winbindd_read_reply(ctx, response) == -1) {
768 : /* Set ENOENT for consistency. Required by some apps */
769 0 : errno = ENOENT;
770 :
771 0 : return NSS_STATUS_UNAVAIL;
772 : }
773 :
774 : /* Throw away extra data if client didn't request it */
775 255645 : if (response == &lresponse) {
776 119962 : winbindd_free_response(response);
777 : }
778 :
779 : /* Copy reply data from socket */
780 255645 : if (response->result != WINBINDD_OK) {
781 10285 : return NSS_STATUS_NOTFOUND;
782 : }
783 :
784 245360 : return NSS_STATUS_SUCCESS;
785 : }
786 :
787 : /* Handle simple types of requests */
788 :
789 537156 : NSS_STATUS winbindd_request_response(struct winbindd_context *ctx,
790 : int req_type,
791 : struct winbindd_request *request,
792 : struct winbindd_response *response)
793 : {
794 537156 : NSS_STATUS status = NSS_STATUS_UNAVAIL;
795 537156 : bool release_global_ctx = false;
796 :
797 537156 : if (ctx == NULL) {
798 521925 : ctx = get_wb_global_ctx();
799 521925 : release_global_ctx = true;
800 : }
801 :
802 537156 : status = winbindd_send_request(ctx, req_type, 0, request);
803 537156 : if (status != NSS_STATUS_SUCCESS) {
804 284460 : goto out;
805 : }
806 252589 : status = winbindd_get_response(ctx, response);
807 :
808 537263 : out:
809 537156 : if (release_global_ctx) {
810 520764 : put_wb_global_ctx();
811 : }
812 537156 : return status;
813 : }
814 :
815 3180 : NSS_STATUS winbindd_priv_request_response(struct winbindd_context *ctx,
816 : int req_type,
817 : struct winbindd_request *request,
818 : struct winbindd_response *response)
819 : {
820 3180 : NSS_STATUS status = NSS_STATUS_UNAVAIL;
821 3180 : bool release_global_ctx = false;
822 :
823 3180 : if (ctx == NULL) {
824 3180 : ctx = get_wb_global_ctx();
825 3180 : release_global_ctx = true;
826 : }
827 :
828 3180 : status = winbindd_send_request(ctx, req_type, 1, request);
829 3180 : if (status != NSS_STATUS_SUCCESS) {
830 124 : goto out;
831 : }
832 3056 : status = winbindd_get_response(ctx, response);
833 :
834 3180 : out:
835 3180 : if (release_global_ctx) {
836 3180 : put_wb_global_ctx();
837 : }
838 3180 : return status;
839 : }
840 :
841 : /* Create and free winbindd context */
842 :
843 260 : struct winbindd_context *winbindd_ctx_create(void)
844 : {
845 : struct winbindd_context *ctx;
846 :
847 260 : ctx = calloc(1, sizeof(struct winbindd_context));
848 :
849 260 : if (!ctx) {
850 0 : return NULL;
851 : }
852 :
853 260 : ctx->winbindd_fd = -1;
854 :
855 260 : return ctx;
856 : }
857 :
858 260 : void winbindd_ctx_free(struct winbindd_context *ctx)
859 : {
860 260 : winbind_close_sock(ctx);
861 260 : free(ctx);
862 260 : }
|