00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "winbind_client.h"
00028
00029 BOOL winbind_env_set( void );
00030 BOOL winbind_off( void );
00031 BOOL winbind_on( void );
00032
00033
00034
00035 int winbindd_fd = -1;
00036 static int is_privileged = 0;
00037
00038
00039
00040 void free_response(struct winbindd_response *response)
00041 {
00042
00043
00044 if (response)
00045 SAFE_FREE(response->extra_data.data);
00046 }
00047
00048
00049
00050 void init_request(struct winbindd_request *request, int request_type)
00051 {
00052 request->length = sizeof(struct winbindd_request);
00053
00054 request->cmd = (enum winbindd_cmd)request_type;
00055 request->pid = getpid();
00056
00057 }
00058
00059
00060
00061 static void init_response(struct winbindd_response *response)
00062 {
00063
00064
00065 response->result = WINBINDD_ERROR;
00066 }
00067
00068
00069
00070 void close_sock(void)
00071 {
00072 if (winbindd_fd != -1) {
00073 close(winbindd_fd);
00074 winbindd_fd = -1;
00075 }
00076 }
00077
00078 #define CONNECT_TIMEOUT 30
00079
00080
00081 #define RECURSION_LIMIT 3
00082
00083 static int make_nonstd_fd_internals(int fd, int limit )
00084 {
00085 int new_fd;
00086 if (fd >= 0 && fd <= 2) {
00087 #ifdef F_DUPFD
00088 if ((new_fd = fcntl(fd, F_DUPFD, 3)) == -1) {
00089 return -1;
00090 }
00091
00092 if (new_fd < 3) {
00093 close(new_fd);
00094 return -1;
00095 }
00096 close(fd);
00097 return new_fd;
00098 #else
00099 if (limit <= 0)
00100 return -1;
00101
00102 new_fd = dup(fd);
00103 if (new_fd == -1)
00104 return -1;
00105
00106
00107 new_fd = make_nonstd_fd_internals(new_fd, limit - 1);
00108 close(fd);
00109 return new_fd;
00110 #endif
00111 }
00112 return fd;
00113 }
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123 static int make_safe_fd(int fd)
00124 {
00125 int result, flags;
00126 int new_fd = make_nonstd_fd_internals(fd, RECURSION_LIMIT);
00127 if (new_fd == -1) {
00128 close(fd);
00129 return -1;
00130 }
00131
00132
00133 #ifdef O_NONBLOCK
00134 #define FLAG_TO_SET O_NONBLOCK
00135 #else
00136 #ifdef SYSV
00137 #define FLAG_TO_SET O_NDELAY
00138 #else
00139 #define FLAG_TO_SET FNDELAY
00140 #endif
00141 #endif
00142
00143 if ((flags = fcntl(new_fd, F_GETFL)) == -1) {
00144 close(new_fd);
00145 return -1;
00146 }
00147
00148 flags |= FLAG_TO_SET;
00149 if (fcntl(new_fd, F_SETFL, flags) == -1) {
00150 close(new_fd);
00151 return -1;
00152 }
00153
00154 #undef FLAG_TO_SET
00155
00156
00157 #ifdef FD_CLOEXEC
00158 result = flags = fcntl(new_fd, F_GETFD, 0);
00159 if (flags >= 0) {
00160 flags |= FD_CLOEXEC;
00161 result = fcntl( new_fd, F_SETFD, flags );
00162 }
00163 if (result < 0) {
00164 close(new_fd);
00165 return -1;
00166 }
00167 #endif
00168 return new_fd;
00169 }
00170
00171
00172
00173 static int winbind_named_pipe_sock(const char *dir)
00174 {
00175 struct sockaddr_un sunaddr;
00176 struct stat st;
00177 pstring path;
00178 int fd;
00179 int wait_time;
00180 int slept;
00181
00182
00183
00184 if (lstat(dir, &st) == -1) {
00185 errno = ENOENT;
00186 return -1;
00187 }
00188
00189 if (!S_ISDIR(st.st_mode) ||
00190 (st.st_uid != 0 && st.st_uid != geteuid())) {
00191 errno = ENOENT;
00192 return -1;
00193 }
00194
00195
00196
00197 strncpy(path, dir, sizeof(path) - 1);
00198 path[sizeof(path) - 1] = '\0';
00199
00200 strncat(path, "/", sizeof(path) - 1 - strlen(path));
00201 path[sizeof(path) - 1] = '\0';
00202
00203 strncat(path, WINBINDD_SOCKET_NAME, sizeof(path) - 1 - strlen(path));
00204 path[sizeof(path) - 1] = '\0';
00205
00206 ZERO_STRUCT(sunaddr);
00207 sunaddr.sun_family = AF_UNIX;
00208 strncpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path) - 1);
00209
00210
00211
00212
00213
00214 if (lstat(path, &st) == -1) {
00215 errno = ENOENT;
00216 return -1;
00217 }
00218
00219
00220
00221 if (!S_ISSOCK(st.st_mode) ||
00222 (st.st_uid != 0 && st.st_uid != geteuid())) {
00223 errno = ENOENT;
00224 return -1;
00225 }
00226
00227
00228
00229 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
00230 return -1;
00231 }
00232
00233
00234
00235 if ((fd = make_safe_fd( fd)) == -1) {
00236 return fd;
00237 }
00238
00239 for (wait_time = 0; connect(fd, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1;
00240 wait_time += slept) {
00241 struct timeval tv;
00242 fd_set w_fds;
00243 int ret;
00244 int connect_errno = 0;
00245 socklen_t errnosize;
00246
00247 if (wait_time >= CONNECT_TIMEOUT)
00248 goto error_out;
00249
00250 switch (errno) {
00251 case EINPROGRESS:
00252 FD_ZERO(&w_fds);
00253 FD_SET(fd, &w_fds);
00254 tv.tv_sec = CONNECT_TIMEOUT - wait_time;
00255 tv.tv_usec = 0;
00256
00257 ret = select(fd + 1, NULL, &w_fds, NULL, &tv);
00258
00259 if (ret > 0) {
00260 errnosize = sizeof(connect_errno);
00261
00262 ret = getsockopt(fd, SOL_SOCKET,
00263 SO_ERROR, &connect_errno, &errnosize);
00264
00265 if (ret >= 0 && connect_errno == 0) {
00266
00267 goto out;
00268 }
00269 }
00270
00271 slept = CONNECT_TIMEOUT;
00272 break;
00273 case EAGAIN:
00274 slept = rand() % 3 + 1;
00275 sleep(slept);
00276 break;
00277 default:
00278 goto error_out;
00279 }
00280
00281 }
00282
00283 out:
00284
00285 return fd;
00286
00287 error_out:
00288
00289 close(fd);
00290 return -1;
00291 }
00292
00293
00294
00295 static int winbind_open_pipe_sock(int recursing, int need_priv)
00296 {
00297 #ifdef HAVE_UNIXSOCKET
00298 static pid_t our_pid;
00299 struct winbindd_request request;
00300 struct winbindd_response response;
00301 ZERO_STRUCT(request);
00302 ZERO_STRUCT(response);
00303
00304 if (our_pid != getpid()) {
00305 close_sock();
00306 our_pid = getpid();
00307 }
00308
00309 if ((need_priv != 0) && (is_privileged == 0)) {
00310 close_sock();
00311 }
00312
00313 if (winbindd_fd != -1) {
00314 return winbindd_fd;
00315 }
00316
00317 if (recursing) {
00318 return -1;
00319 }
00320
00321 if ((winbindd_fd = winbind_named_pipe_sock(WINBINDD_SOCKET_DIR)) == -1) {
00322 return -1;
00323 }
00324
00325 is_privileged = 0;
00326
00327
00328
00329 request.flags = WBFLAG_RECURSE;
00330 if ((winbindd_request_response(WINBINDD_INTERFACE_VERSION, &request, &response) != NSS_STATUS_SUCCESS) || (response.data.interface_version != WINBIND_INTERFACE_VERSION)) {
00331 close_sock();
00332 return -1;
00333 }
00334
00335
00336
00337 request.flags = WBFLAG_RECURSE;
00338 if (winbindd_request_response(WINBINDD_PRIV_PIPE_DIR, &request, &response) == NSS_STATUS_SUCCESS) {
00339 int fd;
00340 if ((fd = winbind_named_pipe_sock((char *)response.extra_data.data)) != -1) {
00341 close(winbindd_fd);
00342 winbindd_fd = fd;
00343 is_privileged = 1;
00344 }
00345 }
00346
00347 if ((need_priv != 0) && (is_privileged == 0)) {
00348 return -1;
00349 }
00350
00351 SAFE_FREE(response.extra_data.data);
00352
00353 return winbindd_fd;
00354 #else
00355 return -1;
00356 #endif
00357 }
00358
00359
00360
00361 int write_sock(void *buffer, int count, int recursing, int need_priv)
00362 {
00363 int result, nwritten;
00364
00365
00366
00367 restart:
00368
00369 if (winbind_open_pipe_sock(recursing, need_priv) == -1) {
00370 errno = ENOENT;
00371 return -1;
00372 }
00373
00374
00375
00376 nwritten = 0;
00377
00378 while(nwritten < count) {
00379 struct timeval tv;
00380 fd_set r_fds;
00381
00382
00383
00384
00385 FD_ZERO(&r_fds);
00386 FD_SET(winbindd_fd, &r_fds);
00387 ZERO_STRUCT(tv);
00388
00389 if (select(winbindd_fd + 1, &r_fds, NULL, NULL, &tv) == -1) {
00390 close_sock();
00391 return -1;
00392 }
00393
00394
00395
00396 if (!FD_ISSET(winbindd_fd, &r_fds)) {
00397
00398
00399
00400 result = write(winbindd_fd,
00401 (char *)buffer + nwritten,
00402 count - nwritten);
00403
00404 if ((result == -1) || (result == 0)) {
00405
00406
00407
00408 close_sock();
00409 return -1;
00410 }
00411
00412 nwritten += result;
00413
00414 } else {
00415
00416
00417
00418 close_sock();
00419 goto restart;
00420 }
00421 }
00422
00423 return nwritten;
00424 }
00425
00426
00427
00428 static int read_sock(void *buffer, int count)
00429 {
00430 int nread = 0;
00431 int total_time = 0, selret;
00432
00433 if (winbindd_fd == -1) {
00434 return -1;
00435 }
00436
00437
00438 while(nread < count) {
00439 struct timeval tv;
00440 fd_set r_fds;
00441
00442
00443
00444
00445 FD_ZERO(&r_fds);
00446 FD_SET(winbindd_fd, &r_fds);
00447 ZERO_STRUCT(tv);
00448
00449 tv.tv_sec = 5;
00450
00451 if ((selret = select(winbindd_fd + 1, &r_fds, NULL, NULL, &tv)) == -1) {
00452 close_sock();
00453 return -1;
00454 }
00455
00456 if (selret == 0) {
00457
00458 if (total_time >= 30) {
00459
00460 close_sock();
00461 return -1;
00462 }
00463 total_time += 5;
00464 continue;
00465 }
00466
00467 if (FD_ISSET(winbindd_fd, &r_fds)) {
00468
00469
00470
00471 int result = read(winbindd_fd, (char *)buffer + nread,
00472 count - nread);
00473
00474 if ((result == -1) || (result == 0)) {
00475
00476
00477
00478
00479
00480 close_sock();
00481 return -1;
00482 }
00483
00484 nread += result;
00485
00486 }
00487 }
00488
00489 return nread;
00490 }
00491
00492
00493
00494 int read_reply(struct winbindd_response *response)
00495 {
00496 int result1, result2 = 0;
00497
00498 if (!response) {
00499 return -1;
00500 }
00501
00502
00503
00504 if ((result1 = read_sock(response, sizeof(struct winbindd_response)))
00505 == -1) {
00506
00507 return -1;
00508 }
00509
00510
00511
00512
00513
00514 response->extra_data.data = NULL;
00515
00516
00517
00518 if (response->length > sizeof(struct winbindd_response)) {
00519 int extra_data_len = response->length -
00520 sizeof(struct winbindd_response);
00521
00522
00523
00524 if (!(response->extra_data.data = malloc(extra_data_len))) {
00525 return -1;
00526 }
00527
00528 if ((result2 = read_sock(response->extra_data.data, extra_data_len))
00529 == -1) {
00530 free_response(response);
00531 return -1;
00532 }
00533 }
00534
00535
00536
00537 return result1 + result2;
00538 }
00539
00540 BOOL winbind_env_set( void )
00541 {
00542 char *env;
00543
00544 if ((env=getenv(WINBINDD_DONT_ENV)) != NULL) {
00545 if(strcmp(env, "1") == 0) {
00546 return True;
00547 }
00548 }
00549 return False;
00550 }
00551
00552
00553
00554
00555
00556 NSS_STATUS winbindd_send_request(int req_type, int need_priv,
00557 struct winbindd_request *request)
00558 {
00559 struct winbindd_request lrequest;
00560
00561
00562
00563 if (winbind_env_set()) {
00564 return NSS_STATUS_NOTFOUND;
00565 }
00566
00567 if (!request) {
00568 ZERO_STRUCT(lrequest);
00569 request = &lrequest;
00570 }
00571
00572
00573
00574 init_request(request, req_type);
00575
00576 if (write_sock(request, sizeof(*request),
00577 request->flags & WBFLAG_RECURSE, need_priv) == -1) {
00578
00579 errno = ENOENT;
00580
00581 return NSS_STATUS_UNAVAIL;
00582 }
00583
00584 if ((request->extra_len != 0) &&
00585 (write_sock(request->extra_data.data, request->extra_len,
00586 request->flags & WBFLAG_RECURSE, need_priv) == -1)) {
00587
00588 errno = ENOENT;
00589
00590 return NSS_STATUS_UNAVAIL;
00591 }
00592
00593 return NSS_STATUS_SUCCESS;
00594 }
00595
00596
00597
00598
00599
00600 NSS_STATUS winbindd_get_response(struct winbindd_response *response)
00601 {
00602 struct winbindd_response lresponse;
00603
00604 if (!response) {
00605 ZERO_STRUCT(lresponse);
00606 response = &lresponse;
00607 }
00608
00609 init_response(response);
00610
00611
00612 if (read_reply(response) == -1) {
00613
00614 errno = ENOENT;
00615
00616 return NSS_STATUS_UNAVAIL;
00617 }
00618
00619
00620 if (response == &lresponse) {
00621 free_response(response);
00622 }
00623
00624
00625 if (response->result != WINBINDD_OK) {
00626 return NSS_STATUS_NOTFOUND;
00627 }
00628
00629 return NSS_STATUS_SUCCESS;
00630 }
00631
00632
00633
00634 NSS_STATUS winbindd_request_response(int req_type,
00635 struct winbindd_request *request,
00636 struct winbindd_response *response)
00637 {
00638 NSS_STATUS status = NSS_STATUS_UNAVAIL;
00639 int count = 0;
00640
00641 while ((status == NSS_STATUS_UNAVAIL) && (count < 10)) {
00642 status = winbindd_send_request(req_type, 0, request);
00643 if (status != NSS_STATUS_SUCCESS)
00644 return(status);
00645 status = winbindd_get_response(response);
00646 count += 1;
00647 }
00648
00649 return status;
00650 }
00651
00652 NSS_STATUS winbindd_priv_request_response(int req_type,
00653 struct winbindd_request *request,
00654 struct winbindd_response *response)
00655 {
00656 NSS_STATUS status = NSS_STATUS_UNAVAIL;
00657 int count = 0;
00658
00659 while ((status == NSS_STATUS_UNAVAIL) && (count < 10)) {
00660 status = winbindd_send_request(req_type, 1, request);
00661 if (status != NSS_STATUS_SUCCESS)
00662 return(status);
00663 status = winbindd_get_response(response);
00664 count += 1;
00665 }
00666
00667 return status;
00668 }
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678 BOOL winbind_off( void )
00679 {
00680 static char *s = CONST_DISCARD(char *, WINBINDD_DONT_ENV "=1");
00681
00682 return putenv(s) != -1;
00683 }
00684
00685 BOOL winbind_on( void )
00686 {
00687 static char *s = CONST_DISCARD(char *, WINBINDD_DONT_ENV "=0");
00688
00689 return putenv(s) != -1;
00690 }
00691