PageRenderTime 49ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/msu.c

https://gitlab.com/msu/msu
C | 960 lines | 735 code | 37 blank | 188 comment | 197 complexity | 67f81231e1f5bab79700940dddfdb80d MD5 | raw file
Possible License(s): GPL-2.0
  1. /*********************************************************************
  2. **
  3. ** Copyright 1999-2004 Oliver Schroeder
  4. **
  5. ** Permission to use, copy, modify, and distribute this
  6. ** software and its documentation for any purpose and
  7. ** without any fee is hereby granted, provided that the
  8. ** above copyright notice and this permission notice
  9. ** appear in all copies of the software and derivative
  10. ** works or modified versions thereof, and that both the
  11. ** copyright notice and this permission and disclaimer
  12. ** notice appear in supporting documentation.
  13. **
  14. ** This software is provided "as is" WITHOUT ANY WARRANTY.
  15. **
  16. ** Oliver Schroeder <progs@o-schroeder.de>
  17. **
  18. *********************************************************************/
  19. #define _GNU_SOURCE
  20. /*********************************************************************
  21. *
  22. * FIXME: check on *BSD Solaris etc.
  23. *
  24. ********************************************************************/
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #if HAVE_CONFIG_H
  28. # include <config.h>
  29. #endif
  30. #if HAVE_PWD_H
  31. # include <pwd.h>
  32. #endif
  33. #if HAVE_SYS_TYPES_H
  34. # include <sys/types.h>
  35. #endif
  36. #if HAVE_SYS_STAT_H
  37. # include <sys/stat.h>
  38. #endif
  39. #if HAVE_UNISTD_H
  40. # include <unistd.h>
  41. #endif
  42. #if HAVE_TERMIOS_H
  43. # include <termios.h>
  44. #endif
  45. #if HAVE_STRING_H
  46. # include <string.h>
  47. #endif
  48. #if HAVE_CTYPE_H
  49. # include <ctype.h>
  50. #endif
  51. #if HAVE_SYSLOG_H
  52. # include <syslog.h>
  53. #endif
  54. #if HAVE_LIBGEN_H
  55. # include <libgen.h>
  56. #endif
  57. #if HAVE_LIBGEN_H
  58. # include <crypt.h>
  59. #endif
  60. #include <grp.h>
  61. /*********************************************************************
  62. **
  63. ** global constants
  64. **
  65. **********************************************************************/
  66. enum
  67. {
  68. UNSPEC = -1,
  69. OK = 0,
  70. FAILED = 1,
  71. NO = 0,
  72. NIL = 0,
  73. YES = 1,
  74. MAX_BUFFER = 512
  75. };
  76. /*********************************************************************
  77. **
  78. ** return values
  79. **
  80. **********************************************************************/
  81. enum EXIT_VALUES
  82. {
  83. WANTED_NOT_FOUND,
  84. PERMISSION_DENIED,
  85. SETGID_FAILED,
  86. SETUID_FAILED,
  87. SHELL_FAILED,
  88. NO_MSUUSER,
  89. MSUUSER_WRONG_USER,
  90. MSUUSER_WRONG_MODE,
  91. MSUUSER_READ_FAILED,
  92. SYNTAX_ERROR,
  93. SWITCH_ERROR,
  94. SHADOW_READ_FAILED,
  95. COMMAND_LINE_ERROR,
  96. GROUP_NOT_FOUND,
  97. NO_MEMORY
  98. };
  99. /*********************************************************************
  100. **
  101. ** global variables
  102. **
  103. **********************************************************************/
  104. char* DEF_SHELL = "/bin/sh"; /* default shell */
  105. char SUSER[MAX_BUFFER];
  106. /*
  107. * modified by config file
  108. */
  109. int NEED_PASSWD = YES; /* user needs to give password */
  110. int WITH_ASTERISK = YES;
  111. /*
  112. * modified by command line
  113. */
  114. int LOGIN_SHELL = NO; /* -l --login */
  115. int CHANGE_GROUP = NO; /* -g --group */
  116. char* EXEC_SHELL = ""; /* -s --shell */
  117. char* WANTED_USER = "";
  118. char* EXEC_COMMAND = (char*) NIL;
  119. char** ADDITIONAL_ARGS = (char**) NIL;
  120. /*********************************************************************
  121. **
  122. ** typedef's
  123. **
  124. **********************************************************************/
  125. typedef struct termios TERMIOS;
  126. typedef struct passwd PWENTRY;
  127. /*
  128. * we use this structure, since getpwnam() and getpwuid() use
  129. * static buffers and the *_r()'s are just plain ill
  130. */
  131. typedef struct
  132. {
  133. char Name[MAX_BUFFER];
  134. char Passwd[MAX_BUFFER];
  135. char PW_DIR[MAX_BUFFER];
  136. uid_t UID;
  137. gid_t GID;
  138. }
  139. USER_ENTRY;
  140. /*********************************************************************
  141. **
  142. ** prototypes
  143. **
  144. **********************************************************************/
  145. int UserOK ( USER_ENTRY* Wanted, USER_ENTRY* User );
  146. int GetPWEntry ( char* Name, int Uid, /*@out@*/ USER_ENTRY* UserEntry );
  147. int GetGrpEntry ( char* Name, USER_ENTRY* UserEntry );
  148. int AuthUser ( USER_ENTRY* User );
  149. void GetShadowPW ( const char *UserName, char *UserPass );
  150. void SetSwitch ( const char *Switch, unsigned int LineNo );
  151. void ParseParams ( int argc, char *argv[] );
  152. static void run_shell ( /*@null@*/ char *shell, const char *command,
  153. char **additional_args, int login );
  154. /*********************************************************************
  155. **
  156. ** main
  157. **
  158. **********************************************************************/
  159. int
  160. main ( int argc, char *argv[] )
  161. {
  162. USER_ENTRY User;
  163. USER_ENTRY Wanted;
  164. (void) snprintf (SUSER, MAX_BUFFER, "%s/msuuser", SYSCONFDIR);
  165. openlog ("msu", LOG_ERR, LOG_AUTH);
  166. ParseParams (argc, argv);
  167. (void) GetPWEntry ("", (int) getuid(), &User);
  168. if (WANTED_USER == "") /* wanna be root */
  169. {
  170. (void) GetPWEntry ("root", UNSPEC, &Wanted);
  171. }
  172. else
  173. {
  174. if ((CHANGE_GROUP == NO)
  175. && (GetPWEntry (WANTED_USER, UNSPEC, &Wanted) != OK))
  176. {
  177. syslog (LOG_CRIT, "'%s' -> '%s' not found.\n",
  178. User.Name, WANTED_USER);
  179. fprintf (stderr, "'%s' -> '%s' not found.\n",
  180. User.Name, WANTED_USER);
  181. exit (WANTED_NOT_FOUND);
  182. }
  183. }
  184. if (CHANGE_GROUP == YES)
  185. {
  186. /* user wants to change his group, so get group id */
  187. if (GetGrpEntry (WANTED_USER , &Wanted) != OK)
  188. {
  189. syslog (LOG_CRIT, "'%s' -> '%s' not found.\n",
  190. User.Name, WANTED_USER);
  191. fprintf (stderr, "'%s' -> '%s' not found.\n",
  192. User.Name, WANTED_USER);
  193. exit (GROUP_NOT_FOUND);
  194. }
  195. }
  196. if (UserOK (&Wanted, &User) != OK)
  197. {
  198. syslog (LOG_CRIT, "%s -> %s permission denied.\n",
  199. User.Name, Wanted.Name);
  200. fprintf (stderr, "%s -> %s permission denied.\n",
  201. User.Name, Wanted.Name);
  202. closelog ();
  203. exit (PERMISSION_DENIED);
  204. }
  205. if (setgid ((gid_t) Wanted.GID) != OK)
  206. {
  207. syslog (LOG_CRIT, "can not set group id.\n");
  208. fprintf (stderr, "can not set group id.\n");
  209. closelog ();
  210. exit (SETGID_FAILED);
  211. }
  212. if (CHANGE_GROUP == NO)
  213. {
  214. if (setuid ((uid_t) Wanted.UID) != OK)
  215. {
  216. syslog (LOG_CRIT, "can not set user id.\n");
  217. fprintf (stderr, "can not set user id.\n");
  218. closelog ();
  219. exit (SETUID_FAILED);
  220. }
  221. }
  222. if (EXEC_SHELL == "")
  223. {
  224. EXEC_SHELL = getenv ("SHELL");
  225. if (EXEC_SHELL == (char*) NIL)
  226. {
  227. EXEC_SHELL = DEF_SHELL;
  228. }
  229. }
  230. if (CHANGE_GROUP == YES)
  231. {
  232. syslog (LOG_CRIT, "%s -> %s\n", User.Name, WANTED_USER);
  233. fprintf (stderr, "%s -> %s\n", User.Name, WANTED_USER);
  234. }
  235. else
  236. {
  237. syslog (LOG_CRIT, "%s -> %s\n", User.Name, Wanted.Name);
  238. fprintf (stderr, "%s -> %s\n", User.Name, Wanted.Name);
  239. }
  240. closelog ();
  241. if (LOGIN_SHELL == YES)
  242. {
  243. /* set some environment variables */
  244. setenv ("HOME", Wanted.PW_DIR, YES);
  245. }
  246. setenv ("USER", Wanted.Name, YES);
  247. run_shell (EXEC_SHELL, EXEC_COMMAND, ADDITIONAL_ARGS, LOGIN_SHELL);
  248. fprintf (stderr, "can not execute shell (%s).\n", EXEC_SHELL);
  249. return (SHELL_FAILED);
  250. }
  251. /*********************************************************************
  252. **
  253. ** get user info from passwd
  254. **
  255. **********************************************************************/
  256. int
  257. GetPWEntry ( char* Name, int Uid, USER_ENTRY* UserEntry )
  258. {
  259. PWENTRY* PW;
  260. UserEntry->Name[0] = '\0';
  261. UserEntry->Passwd[0] = '\0';
  262. UserEntry->PW_DIR[0] = '\0';
  263. UserEntry->UID = UNSPEC;
  264. UserEntry->GID = UNSPEC;
  265. if (Uid != UNSPEC)
  266. {
  267. PW = getpwuid (getuid ());
  268. }
  269. else
  270. {
  271. PW = getpwnam (Name);
  272. }
  273. if (PW == (PWENTRY*) NIL)
  274. {
  275. return (FAILED);
  276. }
  277. strncpy (UserEntry->Name, PW->pw_name, MAX_BUFFER);
  278. strncpy (UserEntry->Passwd, PW->pw_passwd, MAX_BUFFER);
  279. strncpy (UserEntry->PW_DIR, PW->pw_dir, MAX_BUFFER);
  280. UserEntry->UID = PW->pw_uid;
  281. UserEntry->GID = PW->pw_gid;
  282. return (OK);
  283. }
  284. /*********************************************************************
  285. **
  286. ** get group info from /etc/group
  287. ** return: 1 - failed
  288. ** 0 - ok
  289. **
  290. **********************************************************************/
  291. int
  292. GetGrpEntry ( char* Name, USER_ENTRY* UserEntry )
  293. {
  294. struct group* GroupInfo;
  295. GroupInfo = getgrnam(Name);
  296. if (GroupInfo == (struct group *) NIL)
  297. {
  298. return (FAILED);
  299. }
  300. UserEntry->GID = GroupInfo->gr_gid;
  301. return (OK);
  302. }
  303. /*********************************************************************
  304. **
  305. ** check if user is allowed to use msu
  306. **
  307. **********************************************************************/
  308. int
  309. UserOK ( USER_ENTRY* Wanted, USER_ENTRY* User )
  310. {
  311. char* Index;
  312. char* UserList;
  313. char Dummy[MAX_BUFFER];
  314. char Sep;
  315. char* CurSep;
  316. char* Seperators = ": \t";
  317. size_t Len;
  318. unsigned int LineNo;
  319. size_t Dummylen;
  320. int Found = NO;
  321. FILE* MSU_File;
  322. struct stat stats;
  323. /*************************************************
  324. **
  325. ** root may always use msu
  326. **
  327. **************************************************/
  328. if (User->UID == 0)
  329. {
  330. return (OK);
  331. }
  332. /*************************************************
  333. **
  334. ** check permissions off the msu-database
  335. **
  336. **************************************************/
  337. Found = stat (SUSER, & stats);
  338. if (Found != OK)
  339. {
  340. fprintf (stderr, "can not stat msu-database (%s).\n", SUSER);
  341. exit (NO_MSUUSER);
  342. }
  343. if (stats.st_uid != 0)
  344. {
  345. fprintf (stderr, "%s should be owned by root.\n", SUSER);
  346. exit (MSUUSER_WRONG_USER);
  347. }
  348. if (stats.st_mode != 33152) /* 0100600 = regular file, owner rw */
  349. {
  350. fprintf (stderr, "%s should have 600 (only) permissions.\n", SUSER);
  351. exit (MSUUSER_WRONG_MODE);
  352. }
  353. /*************************************************
  354. **
  355. ** open the msu-database
  356. **
  357. **************************************************/
  358. MSU_File = fopen (SUSER, "r");
  359. if (MSU_File == NIL)
  360. {
  361. fprintf (stderr, "can not open msu-database (%s).\n", SUSER);
  362. exit (MSUUSER_READ_FAILED);
  363. }
  364. /*************************************************
  365. **
  366. ** now lookup the calling user in the
  367. ** suser-databse.
  368. **
  369. *************************************************/
  370. Len = strlen (User->Name);
  371. LineNo = 0;
  372. while ((Found == NO) && (feof (MSU_File) == NO))
  373. {
  374. if (fgets (Dummy, MAX_BUFFER, MSU_File) == (char*) NIL)
  375. break; // exit on error
  376. LineNo++;
  377. /*************************************************
  378. **
  379. ** a comment
  380. **
  381. **************************************************/
  382. if (Dummy[0] == '#')
  383. {
  384. continue;
  385. }
  386. /*************************************************
  387. **
  388. ** a config switch?
  389. **
  390. **************************************************/
  391. if (Dummy[0] == '-')
  392. {
  393. SetSwitch (Dummy, LineNo);
  394. continue;
  395. }
  396. CurSep = Seperators;
  397. Index = 0;
  398. while ((*CurSep != 0) && (*CurSep != '\0') && (Index == 0))
  399. {
  400. Index = strchr (Dummy, *CurSep);
  401. if (Index == 0)
  402. {
  403. CurSep++;
  404. }
  405. }
  406. if (Index == 0)
  407. {
  408. /* no 'Sep'-erator, but perhaps username only? */
  409. Dummylen = strlen (Dummy);
  410. if (Dummy[Dummylen - 1] == '\n')
  411. {
  412. Dummy[Dummylen - 1] = '\0';
  413. }
  414. if (strcmp (User->Name, Dummy) == 0)
  415. { /* exakt match */
  416. return (AuthUser (User));
  417. }
  418. else
  419. {
  420. continue;
  421. }
  422. }
  423. if (Index - Dummy != Len)
  424. {
  425. continue;
  426. }
  427. if (strncmp (Dummy, User->Name, Len) == OK)
  428. {
  429. Found = YES;
  430. }
  431. }
  432. if (Found == NO) /* user is not in the database */
  433. {
  434. /* make sure, user has to provide a password */
  435. NEED_PASSWD = 1;
  436. (void) AuthUser (User);
  437. /* but don't let him get what he wants */
  438. return (FAILED);
  439. }
  440. /*************************************************
  441. **
  442. ** ok, the user is allowed to use msu. now look
  443. ** for any restrictions. '\n' and ':' are part of
  444. ** Dummy, so strlen(dummy)-Len is ==2 if no
  445. ** restriction apply!
  446. **
  447. *************************************************/
  448. if (strlen (Dummy) - Len == 2) /* User has no restrictions */
  449. {
  450. return (AuthUser (User));
  451. }
  452. Sep = ',';
  453. UserList = Index + 1;
  454. Len = strlen (Wanted->Name);
  455. while (strlen (UserList) > 0)
  456. {
  457. /*
  458. * FIXME: "user: [space]" does not work
  459. */
  460. while ((isspace (*UserList)) && (*UserList != '\0'))
  461. {
  462. UserList++;
  463. }
  464. if ((Index = strchr (UserList, Sep)) == (char*) OK)
  465. {
  466. break;
  467. }
  468. if ((Index - UserList) != Len)
  469. {
  470. UserList = Index + 1;
  471. continue;
  472. }
  473. if (strncmp (UserList, Wanted->Name, Len) == OK)
  474. {
  475. return (AuthUser (User));
  476. }
  477. UserList = Index + 1;
  478. }
  479. if (strlen (UserList) < Len)
  480. {
  481. return (FAILED);
  482. }
  483. if (strncmp (UserList, Wanted->Name, Len) == OK)
  484. {
  485. return (AuthUser (User));
  486. }
  487. return (FAILED);
  488. }
  489. /*********************************************************************
  490. **
  491. ** set a global switch from config file
  492. **
  493. **********************************************************************/
  494. void
  495. SetSwitch ( const char *Switch, unsigned int LineNo )
  496. {
  497. char* Index;
  498. int SwitchOn;
  499. Index = strchr (Switch, ':');
  500. if (Index == NULL)
  501. {
  502. syslog (LOG_CRIT, "error in msu-database in line %u.\n", LineNo);
  503. fprintf (stderr, "error in msu-database in line %u.\n", LineNo);
  504. exit (SYNTAX_ERROR);
  505. }
  506. Index++;
  507. while ((isspace (*Index)) && (*Index != '\0'))
  508. {
  509. Index++;
  510. }
  511. if (strncasecmp (Index, "ON", 2) == 0)
  512. {
  513. SwitchOn = 1;
  514. }
  515. else if (strncasecmp (Index, "OFF", 3) == 0)
  516. {
  517. SwitchOn = 0;
  518. }
  519. else
  520. {
  521. syslog (LOG_CRIT,
  522. "please set ON or OFF in msu-database in line %u.\n",
  523. LineNo);
  524. fprintf (stderr,
  525. "please set ON or OFF in msu-database in line %u.\n",
  526. LineNo);
  527. exit (SWITCH_ERROR);
  528. }
  529. if (strncmp (Switch, "-echo-asterisk:", 15) == 0)
  530. {
  531. WITH_ASTERISK = SwitchOn;
  532. }
  533. if (strncmp (Switch, "-user-auth:", 11) == 0)
  534. {
  535. NEED_PASSWD = SwitchOn;
  536. }
  537. }
  538. /*********************************************************************
  539. **
  540. ** authenticate user with his password
  541. **
  542. **********************************************************************/
  543. int
  544. AuthUser ( USER_ENTRY* User )
  545. {
  546. int C;
  547. int NumChars;
  548. char Buffer[MAX_BUFFER];
  549. char CRYPT_SALT[MAX_BUFFER];
  550. char UserPass[MAX_BUFFER];
  551. char* Index;
  552. TERMIOS OldModes;
  553. TERMIOS NewModes;
  554. if (NEED_PASSWD == NO)
  555. {
  556. return (OK); /* User is allowed */
  557. }
  558. /*************************************************
  559. * set up terminal
  560. **************************************************/
  561. setbuf (stdin, (char *) 0);
  562. (void) tcgetattr (fileno (stdin), &OldModes);
  563. NewModes = OldModes;
  564. NewModes.c_lflag &= ~(ICANON);
  565. NewModes.c_lflag &= ~(ECHO | ECHOE | ECHOK);
  566. NewModes.c_lflag |= ECHONL;
  567. (void) tcsetattr (fileno (stdin), TCSANOW, &NewModes);
  568. /*************************************************
  569. * read password
  570. **************************************************/
  571. NumChars = 0;
  572. C = 0;
  573. (void) fputs ("enter your password: ", stdout);
  574. (void) fflush (stdout);
  575. while (read (fileno (stdin), &C, 1) > 0)
  576. {
  577. switch (C)
  578. {
  579. case '\n': /* ENTER */
  580. case '\r':
  581. Buffer[NumChars] = '\0';
  582. goto endwhile;
  583. case 127: /* BACKSPACE */
  584. case '\b':
  585. if (NumChars > 0)
  586. {
  587. Buffer[NumChars] = '\0';
  588. NumChars--;
  589. if (WITH_ASTERISK == YES)
  590. {
  591. (void) fputs ("\b \b", stdout);
  592. }
  593. }
  594. else
  595. {
  596. (void) putc ('\a', stdout); /* BEL */
  597. }
  598. break;
  599. case '\025': /* CTRL-U */
  600. if (NumChars <= 0)
  601. {
  602. (void) putc ('\a', stdout); /* BEL */
  603. }
  604. for (C = NumChars; C > 0; C--)
  605. {
  606. Buffer[C] = '\0';
  607. if (WITH_ASTERISK == YES)
  608. {
  609. (void) fputs ("\b \b", stdout);
  610. }
  611. }
  612. NumChars = 0;
  613. break;
  614. default:
  615. Buffer[NumChars] = (char) C;
  616. NumChars++;
  617. if (WITH_ASTERISK == YES)
  618. {
  619. (void) putc ('*', stdout);
  620. }
  621. break;
  622. } // switch()
  623. (void) fflush (stdout);
  624. if (NumChars > MAX_BUFFER)
  625. {
  626. NumChars--;
  627. (void) putc ('\a', stdout); /* BEL */
  628. break;
  629. }
  630. }
  631. endwhile:
  632. Buffer[NumChars] = '\0';
  633. (void) putc ('\n', stdout);
  634. /*************************************************
  635. **
  636. ** restore terminal
  637. **
  638. **************************************************/
  639. (void) tcsetattr (fileno (stdin), TCSANOW, &OldModes);
  640. /*************************************************
  641. **
  642. ** check password
  643. **
  644. **************************************************/
  645. if (strlen (User->Passwd) > 1)
  646. { /* password from PWENTRY */
  647. strncpy (UserPass, User->Passwd, MAX_BUFFER);
  648. }
  649. else
  650. { /* read password from /etc/shadow (eg linux) */
  651. GetShadowPW (User->Name, UserPass);
  652. }
  653. /* at least a salt must be present */
  654. if (strlen (UserPass) < 5)
  655. {
  656. return (FAILED);
  657. }
  658. /*************************************************
  659. **
  660. ** get SALT
  661. **
  662. **************************************************/
  663. if ((strncmp (UserPass, "$1$", 3) == 0)
  664. || (strncmp (UserPass, "$6$", 3) == 0))
  665. {
  666. Index = strchr (&UserPass[3], '$');
  667. Index++;
  668. strncpy (CRYPT_SALT, UserPass, Index - UserPass);
  669. CRYPT_SALT[Index - UserPass] = '\0';
  670. }
  671. else
  672. {
  673. CRYPT_SALT[0] = UserPass[0];
  674. CRYPT_SALT[1] = UserPass[1];
  675. CRYPT_SALT[2] = '\0';
  676. }
  677. if (strcmp (UserPass, crypt (Buffer, CRYPT_SALT)) == 0)
  678. return (OK);
  679. return (FAILED);
  680. }
  681. /*********************************************************************
  682. **
  683. ** read /etc/shadow and get password for 'UserName'
  684. **
  685. **********************************************************************/
  686. void
  687. GetShadowPW (const char *UserName, char *UserPass)
  688. {
  689. FILE *Shadow_File;
  690. char Dummy[MAX_BUFFER];
  691. int Found = 0;
  692. size_t UserLen;
  693. char *Index = 0;
  694. char *Index2 = 0;
  695. Shadow_File = fopen ("/etc/shadow", "r");
  696. if (Shadow_File == 0)
  697. {
  698. fprintf (stderr, "can not open /etc/shadow!\n");
  699. exit (SHADOW_READ_FAILED);
  700. }
  701. UserLen = strlen (UserName);
  702. while ((Found == NO) && (feof (Shadow_File) == NO))
  703. {
  704. (void) fgets (Dummy, MAX_BUFFER, Shadow_File);
  705. Index = strchr (Dummy, ':');
  706. if (UserLen != Index-Dummy)
  707. {
  708. continue;
  709. }
  710. if (strncmp (UserName, Dummy, Index-Dummy) == 0)
  711. {
  712. Found = YES;
  713. }
  714. }
  715. if (Found == NO)
  716. {
  717. return;
  718. }
  719. Index++;
  720. Index2 = strchr (Index, ':');
  721. if (Index2 == (char*) NIL)
  722. {
  723. return;
  724. }
  725. strncpy (UserPass, Index, (size_t) (Index2 - Index));
  726. UserPass[Index2 - Index] = '\0';
  727. (void) fclose (Shadow_File);
  728. }
  729. /*********************************************************************
  730. **
  731. ** print version information
  732. **
  733. **********************************************************************/
  734. void
  735. PrintVersion ()
  736. {
  737. printf ("\n%s v%s (c) 1999-2005 Oliver Schroeder\n\n",
  738. PACKAGE, VERSION);
  739. }
  740. /*********************************************************************
  741. **
  742. ** print a help screen
  743. **
  744. **********************************************************************/
  745. void
  746. PrintHelp (char *ProgName)
  747. {
  748. PrintVersion ();
  749. printf ("\
  750. syntax: %s [options] user [exec-cmd args] \n\
  751. \n\
  752. options: \n\
  753. - | -l | --login use no login shell \n\
  754. -v | --version print version information and exit \n\
  755. -h | --help print this help screen \n\
  756. -s | --shell SHELL use SHELL as shell \n\
  757. -c | --command CMD pass CMD to the shell via -c option \n\
  758. -g | --group change group id instead of userid \n\
  759. \n\
  760. all additional arguments gets passed to the shell as is\n\
  761. \n", basename (ProgName));
  762. }
  763. /*********************************************************************
  764. **
  765. ** parse command line and set global flags/variables
  766. **
  767. **********************************************************************/
  768. void
  769. ParseParams (int argc, char *argv[])
  770. {
  771. int i;
  772. if (argc < 1)
  773. {
  774. return;
  775. }
  776. i = 1;
  777. while ((i < argc) && (WANTED_USER == ""))
  778. {
  779. if ((strcmp (argv[i], "-") == OK)
  780. || (strcmp (argv[i], "-l") == OK)
  781. || (strcmp (argv[i], "--login") == OK))
  782. {
  783. LOGIN_SHELL = 1;
  784. }
  785. else if ((strcmp (argv[i], "-v") == 0)
  786. || (strcmp (argv[i], "--version") == 0))
  787. {
  788. PrintVersion ();
  789. exit (OK);
  790. }
  791. else if ((strcmp (argv[i], "-h") == 0)
  792. || (strcmp (argv[i], "--help") == 0))
  793. {
  794. PrintHelp (argv[0]);
  795. exit (OK);
  796. }
  797. else if ((strcmp (argv[i], "-g") == 0)
  798. || (strcmp (argv[i], "--group") == 0))
  799. {
  800. CHANGE_GROUP = YES;
  801. }
  802. else if ((strcmp (argv[i], "-s") == 0)
  803. || (strcmp (argv[i], "--shell") == 0))
  804. {
  805. i++;
  806. if (i < argc)
  807. {
  808. EXEC_SHELL = argv[i];
  809. }
  810. }
  811. else if ((strcmp (argv[i], "-c") == 0)
  812. || (strcmp (argv[i], "--command") == 0))
  813. {
  814. i++;
  815. if (i < argc)
  816. {
  817. EXEC_COMMAND = argv[i];
  818. }
  819. }
  820. else
  821. {
  822. WANTED_USER = argv[i];
  823. }
  824. i++;
  825. }
  826. if (i < argc)
  827. {
  828. ADDITIONAL_ARGS = argv + i;
  829. }
  830. }
  831. /*********************************************************************
  832. **
  833. ** shamelessly stolen from GNU's shadow suite
  834. **
  835. **********************************************************************/
  836. /* we don't use gettext, maybe we do a FIXME: here */
  837. #define _(TEXT) TEXT
  838. char *
  839. xmalloc (size_t size)
  840. {
  841. char *ptr;
  842. ptr = malloc (size);
  843. if ((ptr == 0) && (size > 0))
  844. {
  845. fprintf (stderr, _("malloc(%d) failed\n"), (int) size);
  846. exit (NO_MEMORY);
  847. }
  848. return ptr;
  849. }
  850. /* borrowed from GNU sh-utils' "su.c" */
  851. static int
  852. elements (char **arr)
  853. {
  854. int n = 0;
  855. for (n = 0; *arr; ++arr)
  856. ++n;
  857. return n;
  858. }
  859. /* borrowed from GNU sh-utils' "su.c" */
  860. static void
  861. run_shell (char *shell, const char *command, char **additional_args,
  862. int login)
  863. {
  864. const char **args;
  865. int argno = 1;
  866. char cmd[BUFSIZ];
  867. size_t cmd_len_left = sizeof (cmd) - 1;
  868. if (shell == (char*) NIL)
  869. return;
  870. cmd[0] = '\0';
  871. if (additional_args)
  872. args = (const char **)
  873. xmalloc (sizeof (char *) * (10 + elements (additional_args)));
  874. else
  875. args = (const char **) xmalloc (sizeof (char *) * 10);
  876. if (login == YES)
  877. {
  878. char *arg0;
  879. char *shell_basename;
  880. shell_basename = basename (shell);
  881. arg0 = xmalloc (strlen (shell_basename) + 2);
  882. arg0[0] = '-';
  883. strcpy (arg0 + 1, shell_basename);
  884. args[0] = arg0;
  885. }
  886. else
  887. args[0] = basename (shell);
  888. if ((command != (char*) NIL) || (additional_args) != (char**) NIL)
  889. args[argno++] = "-c";
  890. if (command != (char*) NIL)
  891. {
  892. if (strlen (command) > cmd_len_left)
  893. {
  894. fprintf (stderr, _("Command line args too long\n"));
  895. exit (COMMAND_LINE_ERROR);
  896. }
  897. strcat (cmd, command);
  898. cmd_len_left -= strlen (command);
  899. }
  900. if (additional_args)
  901. for (; *additional_args; ++additional_args)
  902. {
  903. if ((strlen (*additional_args) + 1) > cmd_len_left)
  904. {
  905. fprintf (stderr, _("Command line args too long\n"));
  906. exit (COMMAND_LINE_ERROR);
  907. }
  908. if (cmd[0] != NIL)
  909. {
  910. strcat (cmd, " ");
  911. cmd_len_left--;
  912. }
  913. strcat (cmd, *additional_args);
  914. cmd_len_left -= strlen (*additional_args);
  915. }
  916. if (cmd[0])
  917. args[argno++] = cmd;
  918. args[argno] = NULL;
  919. (void) execv (shell, (char **) args);
  920. fprintf (stderr, _("No shell\n"));
  921. syslog (LOG_CRIT, "Cannot execute %s\n", shell);
  922. }
  923. /* vim:set ai et sts=0 sw=8 ts=8 tw=80: */