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 #include "winbind_client.h"
00026
00027 #ifndef PRINTF_ATTRIBUTE
00028 #define PRINTF_ATTRIBUTE(m, n)
00029 #endif
00030
00031 #ifndef HAVE_ASPRINTF_DECL
00032
00033 int asprintf(char **,const char *, ...) PRINTF_ATTRIBUTE(2,3);
00034 #endif
00035
00036 #ifdef HAVE_NS_API_H
00037 #undef VOLATILE
00038 #undef STATIC
00039 #undef DYNAMIC
00040 #include <ns_daemon.h>
00041 #endif
00042
00043
00044
00045
00046
00047 #define MAX_GETPWENT_USERS 250
00048 #define MAX_GETGRENT_USERS 250
00049
00050
00051
00052 extern int winbindd_fd;
00053
00054 #ifdef HAVE_NS_API_H
00055
00056
00057
00058 static int send_next_request(nsd_file_t *, struct winbindd_request *);
00059 static int do_list(int state, nsd_file_t *rq);
00060
00061 static nsd_file_t *current_rq = NULL;
00062 static int current_winbind_xid = 0;
00063 static int next_winbind_xid = 0;
00064
00065 typedef struct winbind_xid {
00066 int xid;
00067 nsd_file_t *rq;
00068 struct winbindd_request *request;
00069 struct winbind_xid *next;
00070 } winbind_xid_t;
00071
00072 static winbind_xid_t *winbind_xids = (winbind_xid_t *)0;
00073
00074 static int
00075 winbind_xid_new(int xid, nsd_file_t *rq, struct winbindd_request *request)
00076 {
00077 winbind_xid_t *new;
00078
00079 nsd_logprintf(NSD_LOG_LOW,
00080 "entering winbind_xid_new xid = %d rq = 0x%x, request = 0x%x\n",
00081 xid, rq, request);
00082 new = (winbind_xid_t *)nsd_calloc(1,sizeof(winbind_xid_t));
00083 if (!new) {
00084 nsd_logprintf(NSD_LOG_RESOURCE,"winbind_xid_new: failed malloc\n");
00085 return NSD_ERROR;
00086 }
00087
00088 new->xid = xid;
00089 new->rq = rq;
00090 new->request = request;
00091 new->next = winbind_xids;
00092 winbind_xids = new;
00093
00094 return NSD_CONTINUE;
00095 }
00096
00097
00098
00099
00100
00101 nsd_file_t *
00102 winbind_xid_lookup(int xid, struct winbindd_request **requestp)
00103 {
00104 winbind_xid_t **last, *dx;
00105 nsd_file_t *result=0;
00106
00107 for (last = &winbind_xids, dx = winbind_xids; dx && (dx->xid != xid);
00108 last = &dx->next, dx = dx->next);
00109 if (dx) {
00110 *last = dx->next;
00111 result = dx->rq;
00112 *requestp = dx->request;
00113 SAFE_FREE(dx);
00114 }
00115 nsd_logprintf(NSD_LOG_LOW,
00116 "entering winbind_xid_lookup xid = %d rq = 0x%x, request = 0x%x\n",
00117 xid, result, dx->request);
00118
00119 return result;
00120 }
00121
00122 static int
00123 winbind_startnext_timeout(nsd_file_t **rqp, nsd_times_t *to)
00124 {
00125 nsd_file_t *rq;
00126 struct winbindd_request *request;
00127
00128 nsd_logprintf(NSD_LOG_MIN, "timeout (winbind startnext)\n");
00129 rq = to->t_file;
00130 *rqp = rq;
00131 nsd_timeout_remove(rq);
00132 request = to->t_clientdata;
00133 return(send_next_request(rq, request));
00134 }
00135
00136 static void
00137 dequeue_request(void)
00138 {
00139 nsd_file_t *rq;
00140 struct winbindd_request *request;
00141
00142
00143
00144
00145 if (winbind_xids) {
00146 nsd_logprintf(NSD_LOG_MIN, "timeout (winbind) unqueue xid %d\n",
00147 current_winbind_xid);
00148 rq = winbind_xid_lookup(current_winbind_xid++, &request);
00149
00150 nsd_timeout_new(rq,1,winbind_startnext_timeout,request);
00151 }
00152 }
00153
00154 static int
00155 do_request(nsd_file_t *rq, struct winbindd_request *request)
00156 {
00157 if (winbind_xids == NULL) {
00158
00159
00160
00161
00162 nsd_logprintf(NSD_LOG_MIN, "lookup (winbind) sending request\n");
00163 return(send_next_request(rq, request));
00164 } else {
00165
00166
00167
00168
00169 nsd_logprintf(NSD_LOG_MIN,
00170 "lookup (winbind): queue request xid = %d\n",
00171 next_winbind_xid);
00172 return(winbind_xid_new(next_winbind_xid++, rq, request));
00173 }
00174 }
00175
00176 static int
00177 winbind_callback(nsd_file_t **rqp, int fd)
00178 {
00179 struct winbindd_response response;
00180 nsd_file_t *rq;
00181 NSS_STATUS status;
00182 char * result = NULL;
00183 size_t rlen;
00184
00185 dequeue_request();
00186
00187 nsd_logprintf(NSD_LOG_MIN, "entering callback (winbind)\n");
00188
00189 rq = current_rq;
00190 *rqp = rq;
00191
00192 nsd_timeout_remove(rq);
00193 nsd_callback_remove(fd);
00194
00195 ZERO_STRUCT(response);
00196 status = winbindd_get_response(&response);
00197
00198 if (status != NSS_STATUS_SUCCESS) {
00199
00200 free_response(&response);
00201 nsd_logprintf(NSD_LOG_MIN,
00202 "callback (winbind) returning not found, status = %d\n",
00203 status);
00204
00205 switch (status) {
00206 case NSS_STATUS_UNAVAIL:
00207 rq->f_status = NS_UNAVAIL;
00208 break;
00209 case NSS_STATUS_TRYAGAIN:
00210 rq->f_status = NS_TRYAGAIN;
00211 break;
00212 case NSS_STATUS_NOTFOUND:
00213
00214 default:
00215 rq->f_status = NS_NOTFOUND;
00216 }
00217
00218 return NSD_NEXT;
00219 }
00220
00221 switch ((int)rq->f_cmd_data) {
00222 case WINBINDD_WINS_BYNAME:
00223 case WINBINDD_WINS_BYIP:
00224 nsd_logprintf(NSD_LOG_MIN,
00225 "callback (winbind) WINS_BYNAME | WINS_BYIP\n");
00226
00227 rlen = asprintf(&result, "%s\n", response.data.winsresp);
00228 if (rlen == 0 || result == NULL) {
00229 return NSD_ERROR;
00230 }
00231
00232 free_response(&response);
00233
00234 nsd_logprintf(NSD_LOG_MIN, " %s\n", result);
00235 nsd_set_result(rq, NS_SUCCESS, result, rlen, DYNAMIC);
00236 return NSD_OK;
00237
00238 case WINBINDD_GETPWUID:
00239 case WINBINDD_GETPWNAM:
00240 {
00241 struct winbindd_pw *pw = &response.data.pw;
00242
00243 nsd_logprintf(NSD_LOG_MIN,
00244 "callback (winbind) GETPWUID | GETPWUID\n");
00245
00246 rlen = asprintf(&result,"%s:%s:%d:%d:%s:%s:%s\n",
00247 pw->pw_name,
00248 pw->pw_passwd,
00249 pw->pw_uid,
00250 pw->pw_gid,
00251 pw->pw_gecos,
00252 pw->pw_dir,
00253 pw->pw_shell);
00254 if (rlen == 0 || result == NULL)
00255 return NSD_ERROR;
00256
00257 free_response(&response);
00258
00259 nsd_logprintf(NSD_LOG_MIN, " %s\n", result);
00260 nsd_set_result(rq, NS_SUCCESS, result, rlen, DYNAMIC);
00261 return NSD_OK;
00262 }
00263
00264 case WINBINDD_GETGRNAM:
00265 case WINBINDD_GETGRGID:
00266 {
00267 const struct winbindd_gr *gr = &response.data.gr;
00268 const char * members;
00269
00270 nsd_logprintf(NSD_LOG_MIN,
00271 "callback (winbind) GETGRNAM | GETGRGID\n");
00272
00273 if (gr->num_gr_mem && response.extra_data.data) {
00274 members = response.extra_data.data;
00275 } else {
00276 members = "";
00277 }
00278
00279 rlen = asprintf(&result, "%s:%s:%d:%s\n",
00280 gr->gr_name, gr->gr_passwd, gr->gr_gid, members);
00281 if (rlen == 0 || result == NULL)
00282 return NSD_ERROR;
00283
00284 free_response(&response);
00285
00286 nsd_logprintf(NSD_LOG_MIN, " %s\n", result);
00287 nsd_set_result(rq, NS_SUCCESS, result, rlen, DYNAMIC);
00288 return NSD_OK;
00289 }
00290
00291 case WINBINDD_SETGRENT:
00292 case WINBINDD_SETPWENT:
00293 nsd_logprintf(NSD_LOG_MIN,
00294 "callback (winbind) SETGRENT | SETPWENT\n");
00295 free_response(&response);
00296 return(do_list(1,rq));
00297
00298 case WINBINDD_GETGRENT:
00299 case WINBINDD_GETGRLST:
00300 {
00301 int entries;
00302
00303 nsd_logprintf(NSD_LOG_MIN,
00304 "callback (winbind) GETGRENT | GETGRLIST %d responses\n",
00305 response.data.num_entries);
00306
00307 if (response.data.num_entries) {
00308 const struct winbindd_gr *gr = &response.data.gr;
00309 const char * members;
00310 fstring grp_name;
00311 int i;
00312
00313 gr = (struct winbindd_gr *)response.extra_data.data;
00314 if (! gr ) {
00315 nsd_logprintf(NSD_LOG_MIN, " no extra_data\n");
00316 free_response(&response);
00317 return NSD_ERROR;
00318 }
00319
00320 members = (char *)response.extra_data.data +
00321 (response.data.num_entries * sizeof(struct winbindd_gr));
00322
00323 for (i = 0; i < response.data.num_entries; i++) {
00324 snprintf(grp_name, sizeof(grp_name) - 1, "%s:%s:%d:",
00325 gr->gr_name, gr->gr_passwd, gr->gr_gid);
00326
00327 nsd_append_element(rq, NS_SUCCESS, result, rlen);
00328 nsd_append_result(rq, NS_SUCCESS,
00329 &members[gr->gr_mem_ofs],
00330 strlen(&members[gr->gr_mem_ofs]));
00331
00332
00333
00334
00335
00336 nsd_logprintf(NSD_LOG_MIN, " %s (...)\n", grp_name);
00337
00338 gr++;
00339 }
00340 }
00341
00342 entries = response.data.num_entries;
00343 free_response(&response);
00344 if (entries < MAX_GETPWENT_USERS)
00345 return(do_list(2,rq));
00346 else
00347 return(do_list(1,rq));
00348 }
00349
00350 case WINBINDD_GETPWENT:
00351 {
00352 int entries;
00353
00354 nsd_logprintf(NSD_LOG_MIN,
00355 "callback (winbind) GETPWENT %d responses\n",
00356 response.data.num_entries);
00357
00358 if (response.data.num_entries) {
00359 struct winbindd_pw *pw = &response.data.pw;
00360 int i;
00361
00362 pw = (struct winbindd_pw *)response.extra_data.data;
00363 if (! pw ) {
00364 nsd_logprintf(NSD_LOG_MIN, " no extra_data\n");
00365 free_response(&response);
00366 return NSD_ERROR;
00367 }
00368 for (i = 0; i < response.data.num_entries; i++) {
00369 result = NULL;
00370 rlen = asprintf(&result, "%s:%s:%d:%d:%s:%s:%s",
00371 pw->pw_name,
00372 pw->pw_passwd,
00373 pw->pw_uid,
00374 pw->pw_gid,
00375 pw->pw_gecos,
00376 pw->pw_dir,
00377 pw->pw_shell);
00378
00379 if (rlen != 0 && result != NULL) {
00380 nsd_logprintf(NSD_LOG_MIN, " %s\n",result);
00381 nsd_append_element(rq, NS_SUCCESS, result, rlen);
00382 free(result);
00383 }
00384
00385 pw++;
00386 }
00387 }
00388
00389 entries = response.data.num_entries;
00390 free_response(&response);
00391 if (entries < MAX_GETPWENT_USERS)
00392 return(do_list(2,rq));
00393 else
00394 return(do_list(1,rq));
00395 }
00396
00397 case WINBINDD_ENDGRENT:
00398 case WINBINDD_ENDPWENT:
00399 nsd_logprintf(NSD_LOG_MIN, "callback (winbind) ENDGRENT | ENDPWENT\n");
00400 nsd_append_element(rq, NS_SUCCESS, "\n", 1);
00401 free_response(&response);
00402 return NSD_NEXT;
00403
00404 default:
00405 free_response(&response);
00406 nsd_logprintf(NSD_LOG_MIN, "callback (winbind) invalid command %d\n", (int)rq->f_cmd_data);
00407 return NSD_NEXT;
00408 }
00409 }
00410
00411 static int
00412 winbind_timeout(nsd_file_t **rqp, nsd_times_t *to)
00413 {
00414 nsd_file_t *rq;
00415
00416 dequeue_request();
00417
00418 nsd_logprintf(NSD_LOG_MIN, "timeout (winbind)\n");
00419
00420 rq = to->t_file;
00421 *rqp = rq;
00422
00423
00424 nsd_callback_remove(winbindd_fd);
00425 nsd_timeout_remove(rq);
00426
00427 rq->f_status = NS_NOTFOUND;
00428 return NSD_NEXT;
00429 }
00430
00431 static int
00432 send_next_request(nsd_file_t *rq, struct winbindd_request *request)
00433 {
00434 NSS_STATUS status;
00435 long timeout;
00436
00437 switch (rq->f_index) {
00438 case LOOKUP:
00439 timeout = nsd_attr_fetch_long(rq->f_attrs,
00440 "lookup_timeout", 10, 10);
00441 break;
00442 case LIST:
00443 timeout = nsd_attr_fetch_long(rq->f_attrs,
00444 "list_timeout", 10, 10);
00445 break;
00446 default:
00447 nsd_logprintf(NSD_LOG_OPER,
00448 "send_next_request (winbind) "
00449 "invalid request type %d\n", rq->f_index);
00450 rq->f_status = NS_BADREQ;
00451 return NSD_NEXT;
00452 }
00453
00454 nsd_logprintf(NSD_LOG_MIN,
00455 "send_next_request (winbind) %d, timeout = %d sec\n",
00456 rq->f_cmd_data, timeout);
00457 status = winbindd_send_request((int)rq->f_cmd_data,0,request);
00458 SAFE_FREE(request);
00459
00460 if (status != NSS_STATUS_SUCCESS) {
00461 nsd_logprintf(NSD_LOG_MIN,
00462 "send_next_request (winbind) error status = %d\n",
00463 status);
00464 rq->f_status = status;
00465 return NSD_NEXT;
00466 }
00467
00468 current_rq = rq;
00469
00470
00471
00472
00473 nsd_logprintf(NSD_LOG_MIN, "send_next_request (winbind) fd = %d\n",
00474 winbindd_fd);
00475
00476 nsd_callback_new(winbindd_fd, winbind_callback, NSD_READ);
00477 nsd_timeout_new(rq, timeout * 1000, winbind_timeout, NULL);
00478 return NSD_CONTINUE;
00479 }
00480
00481 int init(void)
00482 {
00483 nsd_logprintf(NSD_LOG_MIN, "entering init (winbind)\n");
00484 return(NSD_OK);
00485 }
00486
00487 int lookup(nsd_file_t *rq)
00488 {
00489 char *map;
00490 char *key;
00491 struct winbindd_request *request;
00492
00493 nsd_logprintf(NSD_LOG_MIN, "entering lookup (winbind)\n");
00494 if (! rq)
00495 return NSD_ERROR;
00496
00497 map = nsd_attr_fetch_string(rq->f_attrs, "table", (char*)0);
00498 key = nsd_attr_fetch_string(rq->f_attrs, "key", (char*)0);
00499 if (! map || ! key) {
00500 nsd_logprintf(NSD_LOG_MIN, "lookup (winbind) table or key not defined\n");
00501 rq->f_status = NS_BADREQ;
00502 return NSD_ERROR;
00503 }
00504
00505 nsd_logprintf(NSD_LOG_MIN, "lookup (winbind %s)\n",map);
00506
00507 request = (struct winbindd_request *)nsd_calloc(1,sizeof(struct winbindd_request));
00508 if (! request) {
00509 nsd_logprintf(NSD_LOG_RESOURCE,
00510 "lookup (winbind): failed malloc\n");
00511 return NSD_ERROR;
00512 }
00513
00514 if (strcasecmp(map,"passwd.byuid") == 0) {
00515 request->data.uid = atoi(key);
00516 rq->f_cmd_data = (void *)WINBINDD_GETPWUID;
00517 } else if (strcasecmp(map,"passwd.byname") == 0) {
00518 strncpy(request->data.username, key,
00519 sizeof(request->data.username) - 1);
00520 request->data.username[sizeof(request->data.username) - 1] = '\0';
00521 rq->f_cmd_data = (void *)WINBINDD_GETPWNAM;
00522 } else if (strcasecmp(map,"group.byname") == 0) {
00523 strncpy(request->data.groupname, key,
00524 sizeof(request->data.groupname) - 1);
00525 request->data.groupname[sizeof(request->data.groupname) - 1] = '\0';
00526 rq->f_cmd_data = (void *)WINBINDD_GETGRNAM;
00527 } else if (strcasecmp(map,"group.bygid") == 0) {
00528 request->data.gid = atoi(key);
00529 rq->f_cmd_data = (void *)WINBINDD_GETGRGID;
00530 } else if (strcasecmp(map,"hosts.byname") == 0) {
00531 strncpy(request->data.winsreq, key, sizeof(request->data.winsreq) - 1);
00532 request->data.winsreq[sizeof(request->data.winsreq) - 1] = '\0';
00533 rq->f_cmd_data = (void *)WINBINDD_WINS_BYNAME;
00534 } else if (strcasecmp(map,"hosts.byaddr") == 0) {
00535 strncpy(request->data.winsreq, key, sizeof(request->data.winsreq) - 1);
00536 request->data.winsreq[sizeof(request->data.winsreq) - 1] = '\0';
00537 rq->f_cmd_data = (void *)WINBINDD_WINS_BYIP;
00538 } else {
00539
00540
00541
00542 nsd_logprintf(NSD_LOG_MIN, "lookup (winbind) unknown table\n");
00543 SAFE_FREE(request);
00544 rq->f_status = NS_NOTFOUND;
00545 return NSD_NEXT;
00546 }
00547
00548 return(do_request(rq, request));
00549 }
00550
00551 int list(nsd_file_t *rq)
00552 {
00553 char *map;
00554
00555 nsd_logprintf(NSD_LOG_MIN, "entering list (winbind)\n");
00556 if (! rq)
00557 return NSD_ERROR;
00558
00559 map = nsd_attr_fetch_string(rq->f_attrs, "table", (char*)0);
00560 if (! map ) {
00561 nsd_logprintf(NSD_LOG_MIN, "list (winbind) table not defined\n");
00562 rq->f_status = NS_BADREQ;
00563 return NSD_ERROR;
00564 }
00565
00566 nsd_logprintf(NSD_LOG_MIN, "list (winbind %s)\n",map);
00567
00568 return (do_list(0,rq));
00569 }
00570
00571 static int
00572 do_list(int state, nsd_file_t *rq)
00573 {
00574 char *map;
00575 struct winbindd_request *request;
00576
00577 nsd_logprintf(NSD_LOG_MIN, "entering do_list (winbind) state = %d\n",state);
00578
00579 map = nsd_attr_fetch_string(rq->f_attrs, "table", (char*)0);
00580 request = (struct winbindd_request *)nsd_calloc(1,sizeof(struct winbindd_request));
00581 if (! request) {
00582 nsd_logprintf(NSD_LOG_RESOURCE,
00583 "do_list (winbind): failed malloc\n");
00584 return NSD_ERROR;
00585 }
00586
00587 if (strcasecmp(map,"passwd.byname") == 0) {
00588 switch (state) {
00589 case 0:
00590 rq->f_cmd_data = (void *)WINBINDD_SETPWENT;
00591 break;
00592 case 1:
00593 request->data.num_entries = MAX_GETPWENT_USERS;
00594 rq->f_cmd_data = (void *)WINBINDD_GETPWENT;
00595 break;
00596 case 2:
00597 rq->f_cmd_data = (void *)WINBINDD_ENDPWENT;
00598 break;
00599 default:
00600 nsd_logprintf(NSD_LOG_MIN, "do_list (winbind) unknown state\n");
00601 SAFE_FREE(request);
00602 rq->f_status = NS_NOTFOUND;
00603 return NSD_NEXT;
00604 }
00605 } else if (strcasecmp(map,"group.byname") == 0) {
00606 switch (state) {
00607 case 0:
00608 rq->f_cmd_data = (void *)WINBINDD_SETGRENT;
00609 break;
00610 case 1:
00611 request->data.num_entries = MAX_GETGRENT_USERS;
00612 rq->f_cmd_data = (void *)WINBINDD_GETGRENT;
00613 break;
00614 case 2:
00615 rq->f_cmd_data = (void *)WINBINDD_ENDGRENT;
00616 break;
00617 default:
00618 nsd_logprintf(NSD_LOG_MIN, "do_list (winbind) unknown state\n");
00619 SAFE_FREE(request);
00620 rq->f_status = NS_NOTFOUND;
00621 return NSD_NEXT;
00622 }
00623 } else {
00624
00625
00626
00627 nsd_logprintf(NSD_LOG_MIN, "do_list (winbind) unknown table\n");
00628 SAFE_FREE(request);
00629 rq->f_status = NS_NOTFOUND;
00630 return NSD_NEXT;
00631 }
00632
00633 return(do_request(rq, request));
00634 }
00635
00636 #endif