Changeset 481 for trunk/src/yulectl.c
- Timestamp:
- Jul 18, 2015, 5:06:52 PM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/yulectl.c
r454 r481 24 24 #include <stdlib.h> 25 25 #include <string.h> 26 #include <ctype.h> 26 27 #include <errno.h> 27 28 … … 41 42 #define SH_MAXMSG 209 42 43 44 #if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED) && \ 45 !defined(HAVE_STRUCT_CMSGCRED) && !defined(HAVE_STRUCT_FCRED) && \ 46 !(defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS)) 47 #define SH_REQ_PASSWORD 1 48 #endif 49 43 50 static int sock = -1; 44 static char * sockname = NULL;45 46 51 static char password[15] = ""; 47 48 52 static int verbose = 0; 49 53 … … 86 90 87 91 88 int89 make_named_socket (char * sockname)92 static int 93 create_unix_socket () 90 94 { 91 95 int sock; 92 93 #if 094 struct sockaddr_un name;95 size_t size;96 #else97 (void) sockname;98 #endif99 96 100 97 /* Create the socket. */ … … 107 104 } 108 105 109 #if 0110 /* Bind a name to the socket. */111 name.sun_family = AF_FILE;112 strcpy (name.sun_path, sockname);113 114 /* The size of the address is115 the offset of the start of the filename,116 plus its length,117 plus one for the terminating null byte. */118 size = (offsetof (struct sockaddr_un, sun_path)119 + strlen (name.sun_path) + 1);120 121 if (bind (sock, (struct sockaddr *) &name, size) < 0)122 {123 perror (_("ERROR: bind"));124 return -1;125 }126 #endif127 128 106 return sock; 129 107 } 130 108 131 void109 static void 132 110 termination_handler (int signum) 133 111 { … … 138 116 fprintf(stdout, _("# Terminated on signal %d\n"), signum); 139 117 } 140 #if 0 141 if (sockname != NULL) unlink (sockname); 142 #endif 143 if (sock >= 0 ) close (sock); 144 118 if (sock >= 0 ) 119 close (sock); 145 120 return; 146 121 } 147 122 148 149 int send_to_server (char * serversock, char * message) 123 static char * safe_copy(char * to, const char * from, size_t size) 124 { 125 if (to && from) 126 { 127 strncpy (to, from, size); 128 if (size > 0) 129 to[size-1] = '\0'; 130 else 131 *to = '\0'; 132 } 133 return to; 134 } 135 136 137 static int send_to_server (char * serversock, char * message) 150 138 { 151 139 struct sockaddr_un name; 152 /* size_t size; */153 140 int size; 154 141 int nbytes; … … 168 155 } 169 156 170 /* Send the datagram. 171 nbytes = sendto (sock, message, strlen (message) + 1, 0, 172 (struct sockaddr *) & name, size); 157 /* Send the data. 173 158 */ 174 159 nbytes = send (sock, message, strlen (message) + 1, 0); 175 176 160 if (nbytes < 0) 177 161 { … … 205 189 } 206 190 207 int recv_from_server (char * message)191 static int recv_from_server (char * message) 208 192 { 209 193 int nbytes = 0; … … 211 195 int num = 0; 212 196 int good = -1; 213 int islist = 0;214 197 char * p; 215 198 216 199 if (password[0] == '\0') 217 { 218 if (message[0] == 'L' && message[1] == 'I' && 219 message[2] == 'S' && message[3] == 'T') 220 { 221 islist = 1; 222 } 223 if (message[0] == 'P' && message[1] == 'R' && 224 message[2] == 'O' && message[3] == 'B' && message[4] == 'E' ) 225 { 226 islist = 1; 227 } 228 } 200 p = message; 229 201 else 230 { 231 p = &message[strlen(password)+1]; 232 if (p[0] == 'L' && p[1] == 'I' && 233 p[2] == 'S' && p[3] == 'T') 234 { 235 islist = 1; 236 } 237 if (p[0] == 'P' && p[1] == 'R' && 238 p[2] == 'O' && p[3] == 'B' && p[4] == 'E' ) 239 { 240 islist = 1; 241 } 242 } 243 244 if (islist == 1) 202 p = &message[strlen(password)+1]; 203 204 if (0 == strncmp(p, _("PROBE"), 5) || 205 0 == strncmp(p, _("LIST"), 4)) 245 206 { 246 207 do { 247 /*248 nbytes = recvfrom (sock, recvmsg, SH_MAXMSG, 0, NULL, 0);249 */250 208 nbytes = getline_from_server (sock, recvmsg, SH_MAXMSG); 251 209 if (nbytes < 0) 252 210 { 253 211 if (errno == EAGAIN) 254 { 255 return 0; 256 } 212 return 0; 257 213 else 258 214 { … … 262 218 } 263 219 else if (nbytes == 0) 264 { 265 return 0; 266 } 220 return 0; 221 267 222 if (recvmsg[0] == 'E' && recvmsg[1] == 'N' && recvmsg[2] == 'D') 268 223 { … … 277 232 else 278 233 { 279 /*280 nbytes = recvfrom (sock, recvmsg, SH_MAXMSG, 0, NULL, 0);281 */282 234 nbytes = recv (sock, recvmsg, SH_MAXMSG, 0); 283 235 if (nbytes < 0) … … 290 242 /* Print a diagnostic message. */ 291 243 if (password[0] == '\0') 292 { 293 good = strcmp (message, recvmsg); 294 } 244 good = strcmp (message, recvmsg); 295 245 else 296 { 297 good = strcmp (&message[strlen(password)+1], recvmsg); 298 } 246 good = strcmp (&message[strlen(password)+1], recvmsg); 299 247 300 248 if (0 != good) 301 249 { 302 fprintf (stderr, "%s", _("ERROR: Bounced message != original message (possible reason: superfluous password).\n")); 250 if (0 == strncmp(recvmsg, _("!E:"), 3)) 251 { 252 fputs(recvmsg, stderr); 253 fputc('\n', stderr); 254 } 255 else 256 { 257 fputs (_("ERROR: Bounced message != original message.\n"), stderr); 258 } 303 259 return -1; 304 260 } … … 312 268 } 313 269 314 void usage(char * name) 270 static int check_uuid(const char * in) 271 { 272 int i; 273 const char *cp; 274 275 if (!in || strlen(in) != 36) 276 return -1; 277 for (i=0, cp = in; i <= 36; i++,cp++) { 278 if ((i == 8) || (i == 13) || (i == 18) || 279 (i == 23)) { 280 if (*cp == '-') 281 continue; 282 else 283 return -1; 284 } 285 if (i== 36) 286 if (*cp == 0) 287 continue; 288 if (!isxdigit(*cp)) 289 return -1; 290 } 291 return 0; 292 } 293 294 static int check_command(const char * str) 295 { 296 unsigned int i = 0; 297 char * commands[] = { N_("DELTA:"), N_("RELOAD"), N_("STOP"), N_("SCAN"), 298 N_("CANCEL"), N_("LISTALL"), N_("LIST"), N_("PROBE"), NULL }; 299 300 while (commands[i]) 301 { 302 size_t len = strlen(_(commands[i])); 303 304 if (0 == strncmp(_(commands[i]), str, len)) 305 { 306 if (i == 0) 307 { 308 char * p = strchr(str, ':'); ++p; 309 if ( 0 == check_uuid(p) ) 310 return 0; 311 } 312 else 313 { 314 if (len == strlen(str)) 315 return 0; 316 } 317 } 318 ++i; 319 } 320 321 fprintf (stderr, _("ERROR: invalid command <%s>\n\n"), str); 322 return -1; 323 } 324 325 static void print_usage_and_exit(char * name, int exit_status) 315 326 { 316 327 printf(_("\nUsage : %s [-v][-s server_socket] -c command <client_hostname>\n\n"), … … 325 336 printf("%s", _(" variable YULECTL_PASSWORD (not recommended).\n\n")); 326 337 327 printf("%s", _("Commands: RELOAD <reload configuration>\n")); 328 printf("%s", _(" STOP <terminate>\n")); 329 printf("%s", _(" SCAN <initiate file system check\n")); 330 printf("%s", _(" CANCEL <cancel previous command>\n")); 331 printf("%s", _(" LIST <list queued commands>\n")); 332 printf("%s", _(" LISTALL <list queued and last sent commands>\n")); 333 printf("%s", _(" PROBE <probe all clients for necessity of reload>\n")); 334 return; 338 printf("%s", _("Commands: RELOAD reload configuration\n")); 339 printf("%s", _(" DELTA:<uuid> load delta database with given uuid\n")); 340 printf("%s", _(" STOP terminate\n")); 341 printf("%s", _(" SCAN initiate file system check\n")); 342 printf("%s", _(" CANCEL cancel pending command(s)\n")); 343 printf("%s", _(" LIST list queued commands\n")); 344 printf("%s", _(" LISTALL list queued and last sent commands\n")); 345 printf("%s", _(" PROBE probe all clients for necessity of reload\n")); 346 exit(exit_status); 335 347 } 336 348 … … 339 351 size_t len; 340 352 341 if (!str) 342 return str; 353 if (!str) return str; 343 354 344 355 len = strlen(str); … … 351 362 break; 352 363 } 353 354 364 return str; 355 365 } 356 366 357 void fixup_message (char * message) 358 { 359 char message2[SH_MAXMSG]; 360 char home[4096]; 361 FILE * fp; 367 static int get_home(char * home, size_t size) 368 { 362 369 struct passwd * pwent; 363 char * pw; 364 365 pw = getenv(_("YULECTL_PASSWORD")); 366 if (pw && strlen(pw) < 15) 367 { 368 strcpy(password, pw); 369 strcpy(message2, password); 370 goto do_msg; 371 } 372 370 373 371 pwent = getpwuid(geteuid()); 374 372 if ((pwent == 0) || (pwent->pw_dir == NULL)) … … 379 377 if (NULL != getenv(_("HOME"))) 380 378 { 381 strncpy(home, getenv(_("HOME")), 4096); 382 home[4095] = '\0'; 379 safe_copy(home, getenv(_("HOME")), size); 383 380 } 384 381 else 385 382 { 386 383 fprintf (stderr, _("ERROR: no home directory for euid %ld (tried $HOME and password database).\n"), (long) geteuid()); 387 exit(EXIT_FAILURE);384 return -1; 388 385 } 389 386 } 390 387 else 391 388 { 392 strncpy(home, pwent->pw_dir, 4096); 393 home[4095] = '\0'; 394 } 389 safe_copy(home, pwent->pw_dir, size); 390 } 391 return 0; 392 } 393 394 static int get_passwd(char * message2, size_t size) 395 { 396 char home[4096]; 397 FILE * fp; 398 char * pw; 399 400 /* 1) Password from environment 401 */ 402 pw = getenv(_("YULECTL_PASSWORD")); 403 if (pw && strlen(pw) < 15) 404 { 405 strcpy(password, pw); 406 strcpy(message2, password); 407 return 0; 408 } 409 410 /* 2) Password from $HOME/.yule_cred 411 */ 412 if (get_home(home, sizeof(home)) < 0) 413 return -1; 395 414 396 415 if ( (strlen(home) + strlen(_("/.yulectl_cred")) + 1) > 4096) 397 416 { 398 417 fprintf (stderr, "%s", _("ERROR: path for $HOME is too long.\n")); 399 exit(EXIT_FAILURE);418 return -1; 400 419 } 401 420 strcat(home, _("/.yulectl_cred")); 402 421 fp = fopen(home, "r"); 403 422 404 #if !defined(HAVE_GETPEEREID) && !defined(SO_PEERCRED) && !defined(HAVE_STRUCT_CMSGCRED) && !defined(HAVE_STRUCT_FCRED) && !(defined(HAVE_STRUCT_SOCKCRED) && defined(LOCAL_CREDS))423 #if defined(SH_REQ_PASSWORD) 405 424 if (fp == NULL) 406 425 { … … 415 434 home, (long)geteuid(), (long)getuid()); 416 435 } 417 exit(EXIT_FAILURE);436 return -1; 418 437 } 419 438 #else 420 439 if (fp == NULL) 421 return ;440 return 0; 422 441 #endif 423 442 424 if (NULL == fgets(message2, size of(message2), fp))443 if (NULL == fgets(message2, size, fp)) 425 444 { 426 445 fprintf (stderr, 427 446 _("ERROR: empty or unreadable password file (%s).\n"), 428 447 home); 429 exit(EXIT_FAILURE);448 return -1; 430 449 } 431 450 … … 436 455 fprintf (stderr, "%s", 437 456 _("ERROR: Password too long (max. 14 characters).\n")); 438 exit(EXIT_FAILURE); 439 } 440 457 return -1; 458 } 441 459 strcpy(password, message2); 442 460 fclose(fp); 443 461 444 do_msg: 445 strcat(message2, "@"); 446 447 strncat(message2, message, SH_MAXMSG - strlen(message2) -1); 448 message2[SH_MAXMSG-1] = '\0'; 449 strcpy(message, message2); 462 return 0; 463 } 464 465 static int fixup_message (char * message) 466 { 467 char message_fixed[SH_MAXMSG] = { 0 }; 468 469 if (get_passwd(message_fixed, sizeof(message_fixed)) < 0) 470 return -1; 471 472 if (strlen(message_fixed) > 0) 473 { 474 strcat(message_fixed, "@"); 475 476 strncat(message_fixed, message, SH_MAXMSG - strlen(message_fixed) -1); 477 message_fixed[SH_MAXMSG-1] = '\0'; 478 strcpy(message, message_fixed); 479 } 480 return 0; 481 } 482 483 static int fill_serversock(char * serversock, size_t size) 484 { 485 int status; 486 487 #ifdef HAVE_VSNPRINTF 488 status = snprintf(serversock, size, _("%s/%s.sock"), 489 DEFAULT_PIDDIR, SH_INSTALL_NAME); 490 #else 491 if ((strlen(DEFAULT_PIDDIR) + strlen(SH_INSTALL_NAME) + 1 + 6) > size) 492 status = -1; 493 else 494 status = sprintf (serversock, _("%s/%s.sock"), 495 DEFAULT_PIDDIR, SH_INSTALL_NAME); 496 #endif 497 498 if ((status < 0) || (status > (int)(size-1))) 499 { 500 fprintf(stderr, _("ERROR: Path too long (maximum %d): %s/%s.sock\n"), 501 (int) (size-1), DEFAULT_PIDDIR, SH_INSTALL_NAME); 502 return -1; 503 } 504 return 0; 505 } 506 507 static void checklen(char * command, char * str, size_t maxlen) 508 { 509 if (strlen(str) > maxlen) 510 { 511 fprintf(stderr, _("ERROR: String too long (max %d): %s\n\n"), 512 (int) maxlen, str); 513 print_usage_and_exit (command, EXIT_FAILURE); 514 } 450 515 return; 451 516 } 452 517 518 static void checknull(char * command, char * str) 519 { 520 if (str == NULL || str[0] == '\0') { 521 fprintf(stderr, "%s", _("ERROR: option with missing argument\n\n")); 522 print_usage_and_exit(command, EXIT_FAILURE); 523 } 524 return; 525 } 453 526 454 527 int … … 457 530 458 531 char message[SH_MAXMSG] = ""; 459 char clientcd[1024];460 532 char serversock[256]; 461 int status , size;533 int status; 462 534 int num = 1; 463 535 int flag = 0; 464 465 #ifdef HAVE_VSNPRINTF 466 status = snprintf(serversock, 256, _("%s/%s.sock"), 467 DEFAULT_PIDDIR, SH_INSTALL_NAME); 468 #else 469 if ((strlen(DEFAULT_PIDDIR) + strlen(SH_INSTALL_NAME) + 1 + 6) > 256) 470 { 471 status = -1; 472 } 473 else 474 { 475 status = sprintf (serversock, _("%s/%s.sock"), 476 DEFAULT_PIDDIR, SH_INSTALL_NAME); 477 } 478 #endif 479 480 if ((status < 0) || (status > 255)) 481 { 482 fprintf(stderr, _("ERROR: Path too long (maximum 255): %s/%s.sock\n"), 483 DEFAULT_PIDDIR, SH_INSTALL_NAME); 484 return (EXIT_FAILURE); 485 } 536 537 if (fill_serversock(serversock, sizeof(serversock)) < 0) 538 return (EXIT_FAILURE); 539 486 540 487 541 while (argc > 1 && argv[num][0] == '-') … … 490 544 { 491 545 case 'h': 492 usage(argv[0]); 493 return (EXIT_SUCCESS); 494 546 print_usage_and_exit(argv[0], EXIT_SUCCESS); 547 break; 495 548 case 'v': 496 549 ++verbose; 497 550 break; 498 499 551 case 's': 500 552 --argc; ++num; 501 if (argv[num] == NULL || argv[num][0] == '\0') { 502 usage(argv[0]); 503 fprintf(stderr, "%s", _("ERROR: -s: argument missing\n")); 504 return (EXIT_FAILURE); 505 } else { 506 if (strlen(argv[num]) > 255) 507 { 508 fprintf(stderr, _("ERROR: Path too long: %s\n"), argv[num]); 509 return (EXIT_FAILURE); 510 } 511 strncpy (serversock, argv[num], 256); 512 serversock[255] = '\0'; 513 } 553 checknull(argv[0], argv[num]); 554 checklen(argv[0], argv[num], sizeof(serversock)-1); 555 safe_copy (serversock, argv[num], sizeof(serversock)); 514 556 break; 515 516 557 case 'c': 517 558 --argc; ++num; 518 if (argv[num] == NULL || argv[num][0] == '\0') { 519 usage(argv[0]); 520 fprintf(stderr, "%s", _("ERROR: -c: argument missing\n")); 521 return (EXIT_FAILURE); 522 } else { 523 if (strlen(argv[num]) >= SH_MAXMSG) 524 { 525 fprintf(stderr, _("ERROR: Command too long: %s\n"), 526 argv[num]); 527 return (EXIT_FAILURE); 528 } 529 strncpy (message, argv[num], SH_MAXMSG); 530 message[SH_MAXMSG-1] = '\0'; 531 strncat(message, ":", SH_MAXMSG-strlen(message)-1); 532 message[SH_MAXMSG-1] = '\0'; 533 flag = 1; 534 } 559 checknull(argv[0], argv[num]); 560 checklen(argv[0], argv[num], SH_MAXMSG-1); 561 if (0 != check_command(argv[num])) 562 print_usage_and_exit(argv[0], EXIT_FAILURE); 563 safe_copy(message, argv[num], SH_MAXMSG); 564 strncat(message, ":", SH_MAXMSG-strlen(message)-1); 565 message[SH_MAXMSG-1] = '\0'; 566 flag = 1; 535 567 break; 536 537 568 default: 538 usage(argv[0]);539 fprintf(stderr, _("ERROR: unknown option -%c\n"), argv[num][1]);540 return (EXIT_FAILURE);569 fprintf(stderr, _("ERROR: unknown option -%c\n\n"), argv[num][1]); 570 print_usage_and_exit(argv[0], EXIT_FAILURE); 571 break; 541 572 } 542 573 --argc; ++num; … … 544 575 545 576 if (flag == 0) /* no command given */ 546 { 547 usage(argv[0]); 548 return (EXIT_FAILURE); 549 } 577 print_usage_and_exit(argv[0], EXIT_FAILURE); 550 578 551 579 if (argc > 1) 552 580 { 553 if (strlen(argv[num]) > (SH_MAXMSG - strlen(message) -1)) 554 { 555 fprintf(stderr, _("ERROR: Hostname too long: %s\n"), argv[num]); 556 return (EXIT_FAILURE); 557 } 558 strncat (message, argv[num], SH_MAXMSG -strlen(message) - 1); 581 checklen(argv[0], argv[num], SH_MAXMSG - strlen(message) - 1); 582 strncat (message, argv[num], SH_MAXMSG - strlen(message) - 1); 559 583 message[SH_MAXMSG-1] = '\0'; 560 584 } 561 585 else 562 586 { 563 if ( message[0] == 'P' && message[1] == 'R' &&564 message[2] == 'O' && message[3] == 'B' && message[4] == 'E')587 if (0 == strncmp(message, _("PROBE"), 5) || 588 0 == strncmp(message, _("LIST"), 4)) 565 589 { 566 590 strncat (message, _("dummy"), SH_MAXMSG -strlen(message) - 1); 567 591 message[SH_MAXMSG-1] = '\0'; 568 592 } 569 else if (message[0] == 'L' && message[1] == 'I' &&570 message[2] == 'S' && message[3] == 'T')571 {572 strncat (message, _("dummy"), SH_MAXMSG -strlen(message) - 1);573 message[SH_MAXMSG-1] = '\0';574 }575 593 else 576 594 { 577 595 fprintf(stderr, "%s", _("ERROR: this command requires a hostname\n")); 578 usage(argv[0]); 579 return (EXIT_FAILURE); 580 } 581 } 582 583 fixup_message(message); 584 585 /* OpenBSD wants >= 1024 586 */ 587 if (NULL == getcwd(clientcd, 1024)) 588 { 589 perror(_("ERROR: getcwd")); 590 return (EXIT_FAILURE); 591 } 592 size = strlen(clientcd) + 1 + strlen(CLIENT) + 6; 593 sockname = calloc(1,size); 594 if (!sockname) 595 { 596 perror(_("ERROR: main: malloc")); 597 return (EXIT_FAILURE); 598 } 599 #ifdef HAVE_VSNPRINTF 600 snprintf(sockname, size, _("%s/%s.sock"), clientcd, CLIENT); 601 #else 602 sprintf(sockname, _("%s/%s.sock"), clientcd, CLIENT); 603 #endif 596 print_usage_and_exit(argv[0], EXIT_FAILURE); 597 } 598 } 599 600 if (fixup_message(message) < 0) 601 return (EXIT_FAILURE); 604 602 605 603 /* Make the socket. 606 604 */ 607 sock = make_named_socket (sockname);605 sock = create_unix_socket (); 608 606 if (sock < 0) 609 { 610 return (EXIT_FAILURE); 611 } 607 return (EXIT_FAILURE); 612 608 613 609 /* Set up termination handler. … … 630 626 /* Wait for a reply. 631 627 */ 632 if (message[0] == 'L' && message[1] == 'I' && 633 message[2] == 'S' && message[3] == 'T') 634 { 635 if (verbose) 628 if (verbose) 629 { 630 if (0 == strncmp(message, "LIST", 4)) 636 631 fprintf(stdout, "%s", _("# Waiting for listing.\n")); 637 } 638 else 639 { 640 if (verbose) 632 else 641 633 fprintf(stdout, "%s", _("# Waiting for confirmation.\n")); 642 634 } 635 643 636 status = recv_from_server (message); 644 637 645 638 if (status < 0) 646 639 { 647 fp rintf(stderr, "%s", _("ERROR: receiving data from server failed.\n"));640 fputs(_("ERROR: unexpected or no reply from server.\n"), stderr); 648 641 (void) termination_handler(0); 649 642 return (EXIT_FAILURE);
Note:
See TracChangeset
for help on using the changeset viewer.