1/* 2 Unix SMB/CIFS implementation. 3 4 Windows NT Domain nsswitch module 5 6 Copyright (C) Tim Potter 2000 7 8 This library is free software; you can redistribute it and/or 9 modify it under the terms of the GNU Library General Public 10 License as published by the Free Software Foundation; either 11 version 2 of the License, or (at your option) any later version. 12 13 This library 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 GNU 16 Library General Public License for more details. 17 18 You should have received a copy of the GNU Library General Public 19 License along with this library; if not, write to the 20 Free Software Foundation, Inc., 59 Temple Place - Suite 330, 21 Boston, MA 02111-1307, USA. 22*/ 23 24#include "winbind_client.h" 25 26#ifdef HAVE_NS_API_H 27#undef VOLATILE 28#include <ns_daemon.h> 29#endif 30 31/* Maximum number of users to pass back over the unix domain socket 32 per call. This is not a static limit on the total number of users 33 or groups returned in total. */ 34 35#define MAX_GETPWENT_USERS 250 36#define MAX_GETGRENT_USERS 250 37 38/* Prototypes from wb_common.c */ 39 40extern int winbindd_fd; 41 42#ifdef HAVE_NS_API_H 43 44/* IRIX version */ 45 46static int send_next_request(nsd_file_t *, struct winbindd_request *); 47static int do_list(int state, nsd_file_t *rq); 48 49static nsd_file_t *current_rq = NULL; 50static int current_winbind_xid = 0; 51static int next_winbind_xid = 0; 52 53typedef struct winbind_xid { 54 int xid; 55 nsd_file_t *rq; 56 struct winbindd_request *request; 57 struct winbind_xid *next; 58} winbind_xid_t; 59 60static winbind_xid_t *winbind_xids = (winbind_xid_t *)0; 61 62static int 63winbind_xid_new(int xid, nsd_file_t *rq, struct winbindd_request *request) 64{ 65 winbind_xid_t *new; 66 67 nsd_logprintf(NSD_LOG_LOW, 68 "entering winbind_xid_new xid = %d rq = 0x%x, request = 0x%x\n", 69 xid, rq, request); 70 new = (winbind_xid_t *)nsd_calloc(1,sizeof(winbind_xid_t)); 71 if (!new) { 72 nsd_logprintf(NSD_LOG_RESOURCE,"winbind_xid_new: failed malloc\n"); 73 return NSD_ERROR; 74 } 75 76 new->xid = xid; 77 new->rq = rq; 78 new->request = request; 79 new->next = winbind_xids; 80 winbind_xids = new; 81 82 return NSD_CONTINUE; 83} 84 85/* 86** This routine will look down the xid list and return the request 87** associated with an xid. We remove the record if it is found. 88*/ 89nsd_file_t * 90winbind_xid_lookup(int xid, struct winbindd_request **requestp) 91{ 92 winbind_xid_t **last, *dx; 93 nsd_file_t *result=0; 94 95 for (last = &winbind_xids, dx = winbind_xids; dx && (dx->xid != xid); 96 last = &dx->next, dx = dx->next); 97 if (dx) { 98 *last = dx->next; 99 result = dx->rq; 100 *requestp = dx->request; 101 SAFE_FREE(dx); 102 } 103 nsd_logprintf(NSD_LOG_LOW, 104 "entering winbind_xid_lookup xid = %d rq = 0x%x, request = 0x%x\n", 105 xid, result, dx->request); 106 107 return result; 108} 109 110static int 111winbind_startnext_timeout(nsd_file_t **rqp, nsd_times_t *to) 112{ 113 nsd_file_t *rq; 114 struct winbindd_request *request; 115 116 nsd_logprintf(NSD_LOG_MIN, "timeout (winbind startnext)\n"); 117 rq = to->t_file; 118 *rqp = rq; 119 nsd_timeout_remove(rq); 120 request = to->t_clientdata; 121 return(send_next_request(rq, request)); 122} 123 124static void 125dequeue_request() 126{ 127 nsd_file_t *rq; 128 struct winbindd_request *request; 129 130 /* 131 * Check for queued requests 132 */ 133 if (winbind_xids) { 134 nsd_logprintf(NSD_LOG_MIN, "timeout (winbind) unqueue xid %d\n", 135 current_winbind_xid); 136 rq = winbind_xid_lookup(current_winbind_xid++, &request); 137 /* cause a timeout on the queued request so we can send it */ 138 nsd_timeout_new(rq,1,winbind_startnext_timeout,request); 139 } 140} 141 142static int 143do_request(nsd_file_t *rq, struct winbindd_request *request) 144{ 145 if (winbind_xids == NULL) { 146 /* 147 * No outstanding requests. 148 * Send off the request to winbindd 149 */ 150 nsd_logprintf(NSD_LOG_MIN, "lookup (winbind) sending request\n"); 151 return(send_next_request(rq, request)); 152 } else { 153 /* 154 * Just queue it up for now - previous callout or timout 155 * will start it up 156 */ 157 nsd_logprintf(NSD_LOG_MIN, 158 "lookup (winbind): queue request xid = %d\n", 159 next_winbind_xid); 160 return(winbind_xid_new(next_winbind_xid++, rq, request)); 161 } 162} 163 164static int 165winbind_callback(nsd_file_t **rqp, int fd) 166{ 167 struct winbindd_response response; 168 struct winbindd_pw *pw = &response.data.pw; 169 struct winbindd_gr *gr = &response.data.gr; 170 nsd_file_t *rq; 171 NSS_STATUS status; 172 fstring result; 173 char *members; 174 int i, maxlen; 175 176 dequeue_request(); 177 178 nsd_logprintf(NSD_LOG_MIN, "entering callback (winbind)\n"); 179 180 rq = current_rq; 181 *rqp = rq; 182 183 nsd_timeout_remove(rq); 184 nsd_callback_remove(fd); 185 186 ZERO_STRUCT(response); 187 status = winbindd_get_response(&response); 188 189 if (status != NSS_STATUS_SUCCESS) { 190 /* free any extra data area in response structure */ 191 free_response(&response); 192 nsd_logprintf(NSD_LOG_MIN, 193 "callback (winbind) returning not found, status = %d\n", 194 status); 195 rq->f_status = NS_NOTFOUND; 196 return NSD_NEXT; 197 } 198 199 maxlen = sizeof(result) - 1; 200 201 switch ((int)rq->f_cmd_data) { 202 case WINBINDD_WINS_BYNAME: 203 case WINBINDD_WINS_BYIP: 204 snprintf(result,maxlen,"%s\n",response.data.winsresp); 205 break; 206 case WINBINDD_GETPWUID: 207 case WINBINDD_GETPWNAM: 208 snprintf(result,maxlen,"%s:%s:%d:%d:%s:%s:%s\n", 209 pw->pw_name, 210 pw->pw_passwd, 211 pw->pw_uid, 212 pw->pw_gid, 213 pw->pw_gecos, 214 pw->pw_dir, 215 pw->pw_shell); 216 break; 217 case WINBINDD_GETGRNAM: 218 case WINBINDD_GETGRGID: 219 if (gr->num_gr_mem && response.extra_data) 220 members = response.extra_data; 221 else 222 members = ""; 223 snprintf(result,maxlen,"%s:%s:%d:%s\n", 224 gr->gr_name, gr->gr_passwd, gr->gr_gid, members); 225 break; 226 case WINBINDD_SETGRENT: 227 case WINBINDD_SETPWENT: 228 nsd_logprintf(NSD_LOG_MIN, "callback (winbind) - SETPWENT/SETGRENT\n"); 229 free_response(&response); 230 return(do_list(1,rq)); 231 case WINBINDD_GETGRENT: 232 case WINBINDD_GETGRLST: 233 nsd_logprintf(NSD_LOG_MIN, 234 "callback (winbind) - %d GETGRENT responses\n", 235 response.data.num_entries); 236 if (response.data.num_entries) { 237 gr = (struct winbindd_gr *)response.extra_data; 238 if (! gr ) { 239 nsd_logprintf(NSD_LOG_MIN, " no extra_data\n"); 240 free_response(&response); 241 return NSD_ERROR; 242 } 243 members = (char *)response.extra_data + 244 (response.data.num_entries * sizeof(struct winbindd_gr)); 245 for (i = 0; i < response.data.num_entries; i++) { 246 snprintf(result,maxlen,"%s:%s:%d:%s\n", 247 gr->gr_name, gr->gr_passwd, gr->gr_gid, 248 &members[gr->gr_mem_ofs]); 249 nsd_logprintf(NSD_LOG_MIN, " GETGRENT %s\n",result); 250 nsd_append_element(rq,NS_SUCCESS,result,strlen(result)); 251 gr++; 252 } 253 } 254 i = response.data.num_entries; 255 free_response(&response); 256 if (i < MAX_GETPWENT_USERS) 257 return(do_list(2,rq)); 258 else 259 return(do_list(1,rq)); 260 case WINBINDD_GETPWENT: 261 nsd_logprintf(NSD_LOG_MIN, 262 "callback (winbind) - %d GETPWENT responses\n", 263 response.data.num_entries); 264 if (response.data.num_entries) { 265 pw = (struct winbindd_pw *)response.extra_data; 266 if (! pw ) { 267 nsd_logprintf(NSD_LOG_MIN, " no extra_data\n"); 268 free_response(&response); 269 return NSD_ERROR; 270 } 271 for (i = 0; i < response.data.num_entries; i++) { 272 snprintf(result,maxlen,"%s:%s:%d:%d:%s:%s:%s", 273 pw->pw_name, 274 pw->pw_passwd, 275 pw->pw_uid, 276 pw->pw_gid, 277 pw->pw_gecos, 278 pw->pw_dir, 279 pw->pw_shell); 280 nsd_logprintf(NSD_LOG_MIN, " GETPWENT %s\n",result); 281 nsd_append_element(rq,NS_SUCCESS,result,strlen(result)); 282 pw++; 283 } 284 } 285 i = response.data.num_entries; 286 free_response(&response); 287 if (i < MAX_GETPWENT_USERS) 288 return(do_list(2,rq)); 289 else 290 return(do_list(1,rq)); 291 case WINBINDD_ENDGRENT: 292 case WINBINDD_ENDPWENT: 293 nsd_logprintf(NSD_LOG_MIN, "callback (winbind) - ENDPWENT/ENDGRENT\n"); 294 nsd_append_element(rq,NS_SUCCESS,"\n",1); 295 free_response(&response); 296 return NSD_NEXT; 297 default: 298 free_response(&response); 299 nsd_logprintf(NSD_LOG_MIN, "callback (winbind) - no valid command\n"); 300 return NSD_NEXT; 301 } 302 nsd_logprintf(NSD_LOG_MIN, "callback (winbind) %s\n", result); 303 /* free any extra data area in response structure */ 304 free_response(&response); 305 nsd_set_result(rq,NS_SUCCESS,result,strlen(result),VOLATILE); 306 return NSD_OK; 307} 308 309static int 310winbind_timeout(nsd_file_t **rqp, nsd_times_t *to) 311{ 312 nsd_file_t *rq; 313 314 dequeue_request(); 315 316 nsd_logprintf(NSD_LOG_MIN, "timeout (winbind)\n"); 317 318 rq = to->t_file; 319 *rqp = rq; 320 321 /* Remove the callback and timeout */ 322 nsd_callback_remove(winbindd_fd); 323 nsd_timeout_remove(rq); 324 325 rq->f_status = NS_NOTFOUND; 326 return NSD_NEXT; 327} 328 329static int 330send_next_request(nsd_file_t *rq, struct winbindd_request *request) 331{ 332 NSS_STATUS status; 333 long timeout; 334 335 timeout = 1000; 336 337 nsd_logprintf(NSD_LOG_MIN, "send_next_request (winbind) %d to = %d\n", 338 rq->f_cmd_data, timeout); 339 status = winbindd_send_request((int)rq->f_cmd_data,request); 340 SAFE_FREE(request); 341 342 if (status != NSS_STATUS_SUCCESS) { 343 nsd_logprintf(NSD_LOG_MIN, 344 "send_next_request (winbind) error status = %d\n",status); 345 rq->f_status = status; 346 return NSD_NEXT; 347 } 348 349 current_rq = rq; 350 351 /* 352 * Set up callback and timeouts 353 */ 354 nsd_logprintf(NSD_LOG_MIN, "send_next_request (winbind) fd = %d\n",winbindd_fd); 355 nsd_callback_new(winbindd_fd,winbind_callback,NSD_READ); 356 nsd_timeout_new(rq,timeout,winbind_timeout,(void *)0); 357 return NSD_CONTINUE; 358} 359 360int init(void) 361{ 362 nsd_logprintf(NSD_LOG_MIN, "entering init (winbind)\n"); 363 return(NSD_OK); 364} 365 366int lookup(nsd_file_t *rq) 367{ 368 char *map; 369 char *key; 370 struct winbindd_request *request; 371 372 nsd_logprintf(NSD_LOG_MIN, "entering lookup (winbind)\n"); 373 if (! rq) 374 return NSD_ERROR; 375 376 map = nsd_attr_fetch_string(rq->f_attrs, "table", (char*)0); 377 key = nsd_attr_fetch_string(rq->f_attrs, "key", (char*)0); 378 if (! map || ! key) { 379 nsd_logprintf(NSD_LOG_MIN, "lookup (winbind) table or key not defined\n"); 380 rq->f_status = NS_BADREQ; 381 return NSD_ERROR; 382 } 383 384 nsd_logprintf(NSD_LOG_MIN, "lookup (winbind %s)\n",map); 385 386 request = (struct winbindd_request *)nsd_calloc(1,sizeof(struct winbindd_request)); 387 if (! request) { 388 nsd_logprintf(NSD_LOG_RESOURCE, 389 "lookup (winbind): failed malloc\n"); 390 return NSD_ERROR; 391 } 392 393 if (strcasecmp(map,"passwd.byuid") == 0) { 394 request->data.uid = atoi(key); 395 rq->f_cmd_data = (void *)WINBINDD_GETPWUID; 396 } else if (strcasecmp(map,"passwd.byname") == 0) { 397 strncpy(request->data.username, key, 398 sizeof(request->data.username) - 1); 399 request->data.username[sizeof(request->data.username) - 1] = '\0'; 400 rq->f_cmd_data = (void *)WINBINDD_GETPWNAM; 401 } else if (strcasecmp(map,"group.byname") == 0) { 402 strncpy(request->data.groupname, key, 403 sizeof(request->data.groupname) - 1); 404 request->data.groupname[sizeof(request->data.groupname) - 1] = '\0'; 405 rq->f_cmd_data = (void *)WINBINDD_GETGRNAM; 406 } else if (strcasecmp(map,"group.bygid") == 0) { 407 request->data.gid = atoi(key); 408 rq->f_cmd_data = (void *)WINBINDD_GETGRGID; 409 } else if (strcasecmp(map,"hosts.byname") == 0) { 410 strncpy(request->data.winsreq, key, sizeof(request->data.winsreq) - 1); 411 request->data.winsreq[sizeof(request->data.winsreq) - 1] = '\0'; 412 rq->f_cmd_data = (void *)WINBINDD_WINS_BYNAME; 413 } else if (strcasecmp(map,"hosts.byaddr") == 0) { 414 strncpy(request->data.winsreq, key, sizeof(request->data.winsreq) - 1); 415 request->data.winsreq[sizeof(request->data.winsreq) - 1] = '\0'; 416 rq->f_cmd_data = (void *)WINBINDD_WINS_BYIP; 417 } else { 418 /* 419 * Don't understand this map - just return not found 420 */ 421 nsd_logprintf(NSD_LOG_MIN, "lookup (winbind) unknown table\n"); 422 SAFE_FREE(request); 423 rq->f_status = NS_NOTFOUND; 424 return NSD_NEXT; 425 } 426 427 return(do_request(rq, request)); 428} 429 430int list(nsd_file_t *rq) 431{ 432 char *map; 433 434 nsd_logprintf(NSD_LOG_MIN, "entering list (winbind)\n"); 435 if (! rq) 436 return NSD_ERROR; 437 438 map = nsd_attr_fetch_string(rq->f_attrs, "table", (char*)0); 439 if (! map ) { 440 nsd_logprintf(NSD_LOG_MIN, "list (winbind) table not defined\n"); 441 rq->f_status = NS_BADREQ; 442 return NSD_ERROR; 443 } 444 445 nsd_logprintf(NSD_LOG_MIN, "list (winbind %s)\n",map); 446 447 return (do_list(0,rq)); 448} 449 450static int 451do_list(int state, nsd_file_t *rq) 452{ 453 char *map; 454 struct winbindd_request *request; 455 456 nsd_logprintf(NSD_LOG_MIN, "entering do_list (winbind) state = %d\n",state); 457 458 map = nsd_attr_fetch_string(rq->f_attrs, "table", (char*)0); 459 request = (struct winbindd_request *)nsd_calloc(1,sizeof(struct winbindd_request)); 460 if (! request) { 461 nsd_logprintf(NSD_LOG_RESOURCE, 462 "do_list (winbind): failed malloc\n"); 463 return NSD_ERROR; 464 } 465 466 if (strcasecmp(map,"passwd.byname") == 0) { 467 switch (state) { 468 case 0: 469 rq->f_cmd_data = (void *)WINBINDD_SETPWENT; 470 break; 471 case 1: 472 request->data.num_entries = MAX_GETPWENT_USERS; 473 rq->f_cmd_data = (void *)WINBINDD_GETPWENT; 474 break; 475 case 2: 476 rq->f_cmd_data = (void *)WINBINDD_ENDPWENT; 477 break; 478 default: 479 nsd_logprintf(NSD_LOG_MIN, "do_list (winbind) unknown state\n"); 480 SAFE_FREE(request); 481 rq->f_status = NS_NOTFOUND; 482 return NSD_NEXT; 483 } 484 } else if (strcasecmp(map,"group.byname") == 0) { 485 switch (state) { 486 case 0: 487 rq->f_cmd_data = (void *)WINBINDD_SETGRENT; 488 break; 489 case 1: 490 request->data.num_entries = MAX_GETGRENT_USERS; 491 rq->f_cmd_data = (void *)WINBINDD_GETGRENT; 492 break; 493 case 2: 494 rq->f_cmd_data = (void *)WINBINDD_ENDGRENT; 495 break; 496 default: 497 nsd_logprintf(NSD_LOG_MIN, "do_list (winbind) unknown state\n"); 498 SAFE_FREE(request); 499 rq->f_status = NS_NOTFOUND; 500 return NSD_NEXT; 501 } 502 } else { 503 /* 504 * Don't understand this map - just return not found 505 */ 506 nsd_logprintf(NSD_LOG_MIN, "do_list (winbind) unknown table\n"); 507 SAFE_FREE(request); 508 rq->f_status = NS_NOTFOUND; 509 return NSD_NEXT; 510 } 511 512 return(do_request(rq, request)); 513} 514 515#endif /* HAVE_NS_API_H */ 516