diff options
-rw-r--r-- | COPYING | 340 | ||||
-rw-r--r-- | README | 106 | ||||
-rw-r--r-- | schroot/sbuild-chroot.c | 583 | ||||
-rw-r--r-- | schroot/sbuild-chroot.h | 116 | ||||
-rw-r--r-- | schroot/sbuild-config.c | 441 | ||||
-rw-r--r-- | schroot/sbuild-config.h | 97 | ||||
-rw-r--r-- | schroot/sbuild-session.c | 743 | ||||
-rw-r--r-- | schroot/sbuild-session.h | 108 | ||||
-rw-r--r-- | schroot/schroot.c | 163 | ||||
-rw-r--r-- | schroot/schroot.conf | 14 |
10 files changed, 2711 insertions, 0 deletions
diff --git a/COPYING b/COPYING new file mode 100644 index 00000000..d60c31a9 --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. @@ -0,0 +1,106 @@ +schroot +------- + +Securely enter a chroot and run a command or login shell. + +Build Dependencies +------------------ +libpam0g-dev +libglib2.0-dev + +Building +-------- + +"make". There is not currently any autoconf/make setup, so a simple +Makefile is used. + +Installation +------------ + +There is no installation; it only runs in the build directory. + +schroot must be owned by root:root and be setuid in order to chroot() +and use PAM for authentication and authorisation. + +test.conf must be owned by root:root and NOT be writable by other. + +Configuration +------------- + +Edit test.conf to point to some chroots, and then try it out. + +The file format is as follows. The format is documented in the GLib +GKeyFile class. Chroots start with a single line containing the chroot name: + +[unstable] + +followed by key-value pairs setting properties for the chroot: + +description=Debian unstable + +A text description of the chroot. + +location=/srv/chroot/sid + +The directory the chroot lives in. + +groups=sbuild + +A comma-separated list of users who are allowed to use the chroot +(currently users not in the list are prompted for a password, but this +will be tightened up). + +root-groups=root + +A comma-separated list of groups allowed unauthenticated root access +in the chroot. + +aliases=sid,default + +Alternate names for the chroot. They are interchangable with the main +name. + + +Running +------- + +$ ./schroot -l +default +etch +sid +testing +unstable + +$ ./schroot -i -c sid +Name: sid +Description: Debian unstable +Location: /srv/chroot/sid +Groups: sbuild +Root Groups: root +Aliases: unstable default + +(use --all or -c multiple times to use multiple chroots) + +$ ./schroot -c sid /bin/ls +** (schroot:13021): DEBUG: session uid = 1000, gid = 1000 + +PAM authentication succeeded for user rleigh +Running session in sid chroot: +** (schroot:13022): DEBUG: Running command: /bin/ls +#README# sbuild-chroot.h sbuild-config.h sbuild-session.h schroot.c +Makefile sbuild-chroot.o sbuild-config.o sbuild-session.o schroot.o +sbuild-chroot.c sbuild-config.c sbuild-session.c schroot test.conf + +$ ./schroot -c sid -u root +** (schroot:13031): DEBUG: session uid = 1000, gid = 1000 + +** (schroot:13031): DEBUG: session uid = 0, gid = 0 + +Password: +PAM authentication succeeded for user root +Running session in sid chroot: +** (schroot:13032): DEBUG: Running login shell: /bin/bash + +(if I was in root-groups in test.conf, I would be granted root access +without authentication, but the PAM authorisation step is still +applied; see sbuild_session_run() in sbuild-session.c). diff --git a/schroot/sbuild-chroot.c b/schroot/sbuild-chroot.c new file mode 100644 index 00000000..073a8789 --- /dev/null +++ b/schroot/sbuild-chroot.c @@ -0,0 +1,583 @@ +/* sbuild-chroot - sbuild chroot object + * + * Copyright (C) 2005 Roger Leigh <rleigh@debian.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + *********************************************************************/ + +/** + * SECTION:sbuild-chroot + * @short_description: chroot object + * @title: SbuildChroot + * + */ + + +#include "sbuild-chroot.h" + +enum +{ + PROP_0, + PROP_NAME, + PROP_DESCRIPTION, + PROP_LOCATION, + PROP_GROUPS, + PROP_ROOT_GROUPS, + PROP_ALIASES +}; + +static GObjectClass *parent_class; + +G_DEFINE_TYPE(SbuildChroot, sbuild_chroot, G_TYPE_OBJECT) + +/** + * sbuild_chroot_new: + * + * Creates a new #SbuildChroot. + * + * Returns the newly created #SbuildChroot. + */ +SbuildChroot * +sbuild_chroot_new (void) +{ + return (SbuildChroot *) g_object_new (SBUILD_TYPE_CHROOT, NULL); +} + +/** + * sbuild_chroot_new_from_keyfile: + * @keyfile: the #GKeyFile containing the chroot configuration + * @group: the group in @keyfile to use + * Creates a new #SbuildChroot. + * + * Returns the newly created #SbuildChroot. + */ +SbuildChroot * +sbuild_chroot_new_from_keyfile (GKeyFile *keyfile, + const char *group) +{ + GError *error = NULL; + + char *description = + g_key_file_get_locale_string(keyfile, group, "description", NULL, &error); + if (error != NULL) + { + g_clear_error(&error); + error = NULL; + description = NULL; + } + + char *location = + g_key_file_get_string(keyfile, group, "location", &error); + if (error != NULL) + { + g_clear_error(&error); + error = NULL; + location = NULL; + } + + char **groups = + g_key_file_get_string_list(keyfile, group, "groups", NULL, &error); + if (error != NULL) + { + g_clear_error(&error); + error = NULL; + groups = NULL; + } + + char **root_groups = + g_key_file_get_string_list(keyfile, group, "root-groups", NULL, &error); + if (error != NULL) + { + g_clear_error(&error); + error = NULL; + root_groups = NULL; + } + + char **aliases = + g_key_file_get_string_list(keyfile, group, "aliases", NULL, &error); + if (error != NULL) + { + g_clear_error(&error); + error = NULL; + aliases = NULL; + } + + SbuildChroot *chroot = (SbuildChroot *) g_object_new + (SBUILD_TYPE_CHROOT, + "name", group, + "description", description, + "location", location, + "groups", groups, + "root-groups", root_groups, + "aliases", aliases, + NULL); + + g_free(description); + g_free(location); + g_strfreev(groups); + g_strfreev(root_groups); + g_strfreev(aliases); + + return chroot; +} + +/** + * sbuild_chroot_get_name: + * @code_table: an #SbuildChroot + * + * Get the name of the chroot. + * + * Returns a string. This string points to internally allocated + * storage in the chroot and must not be freed, modified or stored. + */ +const char * +sbuild_chroot_get_name (const SbuildChroot *restrict chroot) +{ + g_return_val_if_fail(SBUILD_IS_CHROOT(chroot), NULL); + + return chroot->name; +} + +/** + * sbuild_chroot_set_name: + * @code_table: an #SbuildChroot. + * @name: the name to set. + * + * Set the name of a chroot. + */ +void +sbuild_chroot_set_name (SbuildChroot *chroot, + const char *name) +{ + g_return_if_fail(SBUILD_IS_CHROOT(chroot)); + + if (chroot->name) + { + g_free(chroot->name); + } + chroot->name = g_strdup(name); + g_object_notify(G_OBJECT(chroot), "name"); +} + +/** + * sbuild_chroot_get_description: + * @code_table: an #SbuildChroot + * + * Get the description of the chroot. + * + * Returns a string. This string points to internally allocated + * storage in the chroot and must not be freed, modified or stored. + */ +const char * +sbuild_chroot_get_description (const SbuildChroot *restrict chroot) +{ + g_return_val_if_fail(SBUILD_IS_CHROOT(chroot), NULL); + + return chroot->description; +} + +/** + * sbuild_chroot_set_description: + * @code_table: an #SbuildChroot. + * @description: the description to set. + * + * Set the description of a chroot. + */ +void +sbuild_chroot_set_description (SbuildChroot *chroot, + const char *description) +{ + g_return_if_fail(SBUILD_IS_CHROOT(chroot)); + + if (chroot->description) + { + g_free(chroot->description); + } + chroot->description = g_strdup(description); + g_object_notify(G_OBJECT(chroot), "description"); +} + +/** + * sbuild_chroot_get_location: + * @code_table: an #SbuildChroot + * + * Get the location of the chroot. + * + * Returns a string. This string points to internally allocated + * storage in the chroot and must not be freed, modified or stored. + */ +const char * +sbuild_chroot_get_location (const SbuildChroot *restrict chroot) +{ + g_return_val_if_fail(SBUILD_IS_CHROOT(chroot), NULL); + + return chroot->location; +} + +/** + * sbuild_chroot_set_location: + * @code_table: an #SbuildChroot. + * @location: the location to set. + * + * Set the location of a chroot. + */ +void +sbuild_chroot_set_location (SbuildChroot *chroot, + const char *location) +{ + g_return_if_fail(SBUILD_IS_CHROOT(chroot)); + + if (chroot->location) + { + g_free(chroot->location); + } + chroot->location = g_strdup(location); + g_object_notify(G_OBJECT(chroot), "location"); +} + +/** + * sbuild_chroot_get_groups: + * @code_table: an #SbuildChroot + * + * Get the groups of the chroot. + * + * Returns a string. This string points to internally allocated + * storage in the chroot and must not be freed, modified or stored. + */ +char ** +sbuild_chroot_get_groups (const SbuildChroot *restrict chroot) +{ + g_return_val_if_fail(SBUILD_IS_CHROOT(chroot), NULL); + + return chroot->groups; +} + +/** + * sbuild_chroot_set_groups: + * @code_table: an #SbuildChroot. + * @groups: the groups to set. + * + * Set the groups of a chroot. + */ +void +sbuild_chroot_set_groups (SbuildChroot *chroot, + char **groups) +{ + g_return_if_fail(SBUILD_IS_CHROOT(chroot)); + + if (chroot->groups) + { + g_strfreev(chroot->groups); + } + chroot->groups = g_strdupv(groups); + g_object_notify(G_OBJECT(chroot), "groups"); +} + +/** + * sbuild_chroot_get_root_groups: + * @code_table: an #SbuildChroot + * + * Get the root groups of the chroot. + * + * Returns a string. This string points to internally allocated + * storage in the chroot and must not be freed, modified or stored. + */ +char ** +sbuild_chroot_get_root_groups (const SbuildChroot *restrict chroot) +{ + g_return_val_if_fail(SBUILD_IS_CHROOT(chroot), NULL); + + return chroot->root_groups; +} + +/** + * sbuild_chroot_set_root_groups: + * @code_table: an #SbuildChroot. + * @groups: the groups to set. + * + * Set the groups of a chroot. + */ +void +sbuild_chroot_set_root_groups (SbuildChroot *chroot, + char **groups) +{ + g_return_if_fail(SBUILD_IS_CHROOT(chroot)); + + if (chroot->root_groups) + { + g_strfreev(chroot->root_groups); + } + chroot->root_groups = g_strdupv(groups); + g_object_notify(G_OBJECT(chroot), "root-groups"); +} + +/** + * sbuild_chroot_get_aliases: + * @code_table: an #SbuildChroot + * + * Get the aliases of the chroot. + * + * Returns a string. This string points to internally allocated + * storage in the chroot and must not be freed, modified or stored. + */ +char ** +sbuild_chroot_get_aliases (const SbuildChroot *restrict chroot) +{ + g_return_val_if_fail(SBUILD_IS_CHROOT(chroot), NULL); + + return chroot->aliases; +} + +/** + * sbuild_chroot_set_aliases: + * @code_table: an #SbuildChroot. + * @aliases: the aliases to set. + * + * Set the aliases of a chroot. + */ +void +sbuild_chroot_set_aliases (SbuildChroot *chroot, + char **aliases) +{ + g_return_if_fail(SBUILD_IS_CHROOT(chroot)); + + if (chroot->aliases) + { + g_strfreev(chroot->aliases); + } + chroot->aliases = g_strdupv(aliases); + g_object_notify(G_OBJECT(chroot), "aliases"); +} + +void sbuild_chroot_print_details (SbuildChroot *chroot, + FILE *file) +{ + g_fprintf(file, "Name: %s\nDescription: %s\nLocation: %s\n", + chroot->name, chroot->description, chroot->location); + g_fprintf(file, "Groups:"); + if (chroot->groups) + for (guint i=0; chroot->groups[i] != NULL; ++i) + g_fprintf(file, " %s", chroot->groups[i]); + g_fprintf(file, "\nRoot Groups:"); + if (chroot->root_groups) + for (guint i=0; chroot->root_groups[i] != NULL; ++i) + g_fprintf(file, " %s", chroot->root_groups[i]); + g_fprintf(file, "\nAliases:"); + if (chroot->aliases) + for (guint i=0; chroot->aliases[i] != NULL; ++i) + g_fprintf(file, " %s", chroot->aliases[i]); + g_fprintf(file, "\n\n"); +} + +static void +sbuild_chroot_init (SbuildChroot *chroot) +{ + g_return_if_fail(SBUILD_IS_CHROOT(chroot)); + + chroot->name = NULL; + chroot->description = NULL; + chroot->location = NULL; + chroot->groups = NULL; + chroot->root_groups = NULL; + chroot->aliases = NULL; +} + +static void +sbuild_chroot_finalize (SbuildChroot *chroot) +{ + g_return_if_fail(SBUILD_IS_CHROOT(chroot)); + + if (chroot->name) + { + g_free (chroot->name); + chroot->name = NULL; + } + if (chroot->description) + { + g_free (chroot->description); + chroot->description = NULL; + } + if (chroot->location) + { + g_free (chroot->location); + chroot->location = NULL; + } + + if (chroot->groups) + { + g_strfreev(chroot->groups); + chroot->groups = NULL; + } + if (chroot->root_groups) + { + g_strfreev(chroot->root_groups); + chroot->root_groups = NULL; + } + if (chroot->aliases) + { + g_strfreev(chroot->aliases); + chroot->aliases = NULL; + } + + if (parent_class->finalize) + parent_class->finalize(G_OBJECT(chroot)); +} + +static void +sbuild_chroot_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + SbuildChroot *chroot; + + g_return_if_fail (object != NULL); + g_return_if_fail (SBUILD_IS_CHROOT (object)); + + chroot = SBUILD_CHROOT(object); + + switch (param_id) + { + case PROP_NAME: + sbuild_chroot_set_name(chroot, g_value_get_string(value)); + break; + case PROP_DESCRIPTION: + sbuild_chroot_set_description(chroot, g_value_get_string(value)); + break; + case PROP_LOCATION: + sbuild_chroot_set_location(chroot, g_value_get_string(value)); + break; + case PROP_GROUPS: + sbuild_chroot_set_groups(chroot, g_value_get_boxed(value)); + break; + case PROP_ROOT_GROUPS: + sbuild_chroot_set_root_groups(chroot, g_value_get_boxed(value)); + break; + case PROP_ALIASES: + sbuild_chroot_set_aliases(chroot, g_value_get_boxed(value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +sbuild_chroot_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + SbuildChroot *chroot; + + g_return_if_fail (object != NULL); + g_return_if_fail (SBUILD_IS_CHROOT (object)); + + chroot = SBUILD_CHROOT(object); + + switch (param_id) + { + case PROP_NAME: + g_value_set_string(value, chroot->name); + break; + case PROP_DESCRIPTION: + g_value_set_string(value, chroot->description); + break; + case PROP_LOCATION: + g_value_set_string(value, chroot->location); + break; + case PROP_GROUPS: + g_value_set_boxed(value, chroot->groups); + break; + case PROP_ROOT_GROUPS: + g_value_set_boxed(value, chroot->root_groups); + break; + case PROP_ALIASES: + g_value_set_boxed(value, chroot->aliases); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +sbuild_chroot_class_init (SbuildChrootClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + parent_class = g_type_class_peek_parent (klass); + + /* Override the virtual finalize, set_property and + get_property methods in the GObject class vtable (which + is contained in CseCanvasClass). */ + gobject_class->finalize = (GObjectFinalizeFunc) sbuild_chroot_finalize; + gobject_class->set_property = (GObjectSetPropertyFunc) sbuild_chroot_set_property; + gobject_class->get_property = (GObjectGetPropertyFunc) sbuild_chroot_get_property; + + g_object_class_install_property + (gobject_class, + PROP_NAME, + g_param_spec_string ("name", "Name", + "The name of the chroot", + "", + (G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT))); + + g_object_class_install_property + (gobject_class, + PROP_DESCRIPTION, + g_param_spec_string ("description", "Description", + "The description of the chroot", + "", + (G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT))); + + g_object_class_install_property + (gobject_class, + PROP_LOCATION, + g_param_spec_string ("location", "Location", + "The location (path) of the chroot", + "", + (G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT))); + + g_object_class_install_property + (gobject_class, + PROP_GROUPS, + g_param_spec_boxed ("groups", "Groups", + "The groups allowed to use this chroot", + G_TYPE_STRV, + (G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT))); + + g_object_class_install_property + (gobject_class, + PROP_ROOT_GROUPS, + g_param_spec_boxed ("root-groups", "Root Groups", + "The groups allowed to use this chroot as root", + G_TYPE_STRV, + (G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT))); + + g_object_class_install_property + (gobject_class, + PROP_ALIASES, + g_param_spec_boxed ("aliases", "Aliases", + "Alternate names for this chroot", + G_TYPE_STRV, + (G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT))); +} + +/* + * Local Variables: + * mode:C + * End: + */ diff --git a/schroot/sbuild-chroot.h b/schroot/sbuild-chroot.h new file mode 100644 index 00000000..dd84ea6a --- /dev/null +++ b/schroot/sbuild-chroot.h @@ -0,0 +1,116 @@ +/* sbuild-chroot - sbuild chroot object + * + * Copyright (C) 2005 Roger Leigh <rleigh@debian.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + *********************************************************************/ + +#ifndef SBUILD_CHROOT_H +#define SBUILD_CHROOT_H + +#include <glib.h> +#include <glib/gprintf.h> +#include <glib-object.h> + +#define SBUILD_TYPE_CHROOT (sbuild_chroot_get_type ()) +#define SBUILD_CHROOT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SBUILD_TYPE_CHROOT, SbuildChroot)) +#define SBUILD_CHROOT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SBUILD_TYPE_CHROOT, SbuildChrootClass)) +#define SBUILD_IS_CHROOT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SBUILD_TYPE_CHROOT)) +#define SBUILD_IS_CHROOT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SBUILD_TYPE_CHROOT)) +#define SBUILD_CHROOT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SBUILD_TYPE_CHROOT, SbuildChrootClass)) + +typedef struct _SbuildChroot SbuildChroot; +typedef struct _SbuildChrootClass SbuildChrootClass; + +struct _SbuildChroot +{ + GObject parent; + gchar *name; + gchar *description; + gchar *location; + char **groups; + char **root_groups; + char **aliases; +}; + +struct _SbuildChrootClass +{ + GObjectClass parent; +}; + + +GType +sbuild_chroot_get_type (void); + +SbuildChroot * +sbuild_chroot_new (void); + +SbuildChroot * +sbuild_chroot_new_from_keyfile (GKeyFile *keyfile, + const char *group); + +const char * +sbuild_chroot_get_name (const SbuildChroot *restrict chroot); + +void +sbuild_chroot_set_name (SbuildChroot *chroot, + const char *name); + +const char * +sbuild_chroot_get_description (const SbuildChroot *restrict chroot); + +void +sbuild_chroot_set_description (SbuildChroot *chroot, + const char *description); + +const char * +sbuild_chroot_get_location (const SbuildChroot *restrict chroot); + +void +sbuild_chroot_set_location (SbuildChroot *chroot, + const char *location); + +char ** +sbuild_chroot_get_groups (const SbuildChroot *restrict chroot); + +void +sbuild_chroot_set_groups (SbuildChroot *chroot, + char **groups); + +char ** +sbuild_chroot_get_root_groups (const SbuildChroot *restrict chroot); + +void +sbuild_chroot_set_root_groups (SbuildChroot *chroot, + char **groups); + +char ** +sbuild_chroot_get_aliases (const SbuildChroot *restrict chroot); + +void +sbuild_chroot_set_aliases (SbuildChroot *chroot, + char **aliases); + +void sbuild_chroot_print_details (SbuildChroot *chroot, + FILE *file); + +#endif /* SBUILD_CHROOT_H */ + +/* + * Local Variables: + * mode:C + * End: + */ diff --git a/schroot/sbuild-config.c b/schroot/sbuild-config.c new file mode 100644 index 00000000..532737c8 --- /dev/null +++ b/schroot/sbuild-config.c @@ -0,0 +1,441 @@ +/* sbuild-config - sbuild config object + * + * Copyright (C) 2005 Roger Leigh <rleigh@debian.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + *********************************************************************/ + +/** + * SECTION:sbuild-config + * @short_description: config object + * @title: SbuildConfig + * + */ + +#define _GNU_SOURCE +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include "sbuild-config.h" + +GQuark +sbuild_config_file_error_quark (void) +{ + static GQuark error_quark = 0; + + if (error_quark == 0) + error_quark = g_quark_from_static_string ("sbuild-config-file-error-quark"); + + return error_quark; +} + +enum +{ + PROP_0, + PROP_CONFIG_FILE +}; + +static GObjectClass *parent_class; + +G_DEFINE_TYPE(SbuildConfig, sbuild_config, G_TYPE_OBJECT) + +/** + * sbuild_config_new: + * + * Creates a new #SbuildConfig. + * + * Returns the newly created #SbuildConfig. + */ +SbuildConfig * +sbuild_config_new (const char *file) +{ + return (SbuildConfig *) g_object_new (SBUILD_TYPE_CONFIG, + "config-file", file, + NULL); +} + +static gboolean +sbuild_config_check_security(int fd, + GError **error) +{ + struct stat statbuf; + if (fstat(fd, &statbuf) < 0) + { + g_set_error(error, + SBUILD_CONFIG_FILE_ERROR, SBUILD_CONFIG_FILE_ERROR_STAT_FAIL, + "failed to stat file: %s", g_strerror(errno)); + return FALSE; + } + + if (statbuf.st_uid != 0 || statbuf.st_gid != 0) + { + g_set_error(error, + SBUILD_CONFIG_FILE_ERROR, SBUILD_CONFIG_FILE_ERROR_OWNERSHIP, + "not owned by user and group root"); + return FALSE; + } + + if (statbuf.st_mode & S_IWOTH) + { + g_set_error(error, + SBUILD_CONFIG_FILE_ERROR, SBUILD_CONFIG_FILE_ERROR_PERMISSIONS, + "others have write permission"); + return FALSE; + } + + if (!S_ISREG(statbuf.st_mode)) + { + g_set_error(error, + SBUILD_CONFIG_FILE_ERROR, SBUILD_CONFIG_FILE_ERROR_NOT_REGULAR, + "not a regular file"); + return FALSE; + } + + return TRUE; +} + +static GList * +sbuild_config_load (const char *file) +{ + /* Use a UNIX fd, for security (no races) */ + int fd = open(file, O_RDONLY|O_NOFOLLOW); + if (fd < 0) + { + g_printerr("%s: failed to load configuration: %s\n", file, g_strerror(errno)); + exit (EXIT_FAILURE); + } + + GError *security_error = NULL; + sbuild_config_check_security(fd, &security_error); + if (security_error) + { + g_printerr("%s: security failure: %s\n", file, security_error->message); + exit (EXIT_FAILURE); + } + + /* Now create an IO Channel and read in the data */ + GIOChannel *channel = g_io_channel_unix_new(fd); + gchar *data = NULL; + gsize size = 0; + GError *read_error = NULL; + + g_io_channel_set_encoding(channel, NULL, NULL); + g_io_channel_read_to_end(channel, &data, &size, &read_error); + if (read_error) + { + g_printerr("%s: read failure: %s\n", file, read_error->message); + exit (EXIT_FAILURE); + } + + GError *close_error = NULL; + g_io_channel_shutdown(channel, FALSE, &close_error); + if (close_error) + { + g_printerr("%s: close failure: %s\n", file, close_error->message); + exit (EXIT_FAILURE); + } + + /* Create key file */ + GKeyFile *keyfile = g_key_file_new(); + g_key_file_set_list_separator(keyfile, ','); + GError *parse_error = NULL; + g_key_file_load_from_data(keyfile, data, size, G_KEY_FILE_NONE, &parse_error); + + if (parse_error) + { + g_printerr("%s: parse failure: %s\n", file, parse_error->message); + exit (EXIT_FAILURE); + } + + /* Create SbuildChroot objects from key file */ + char **groups = g_key_file_get_groups(keyfile, NULL); + GList *list = NULL; + for (guint i=0; groups[i] != NULL; ++i) + { + SbuildChroot *chroot = sbuild_chroot_new_from_keyfile(keyfile, groups[i]); + // sbuild_chroot_print_details(chroot, stdout); + list = g_list_append(list, chroot); + } + g_strfreev(groups); + + return list; +} + +/** + * sbuild_config_set_name: + * @config: an #SbuildConfig. + * @name: the name to set. + * + * Set the name of a config. + */ +static void +sbuild_config_set_config_file (SbuildConfig *config, + const char *file) +{ + g_return_if_fail(SBUILD_IS_CONFIG(config)); + + if (config->file) + { + g_free(config->file); + } + config->file = g_strdup(file); + + g_assert(config->chroots == NULL); + config->chroots = sbuild_config_load(config->file); + + g_object_notify(G_OBJECT(config), "config_file"); +} + +const GList * +sbuild_config_get_chroots (SbuildConfig *config) +{ + g_return_val_if_fail(SBUILD_IS_CONFIG(config), NULL); + + return config->chroots; +} + +static SbuildChroot * +sbuild_config_find_generic (SbuildConfig *config, + const char *name, + GCompareFunc func) +{ + g_return_val_if_fail(SBUILD_IS_CONFIG(config), NULL); + + SbuildChroot *example = sbuild_chroot_new(); + sbuild_chroot_set_name(example, name); + + GList *elem = g_list_find_custom(config->chroots, example, (GCompareFunc) func); + + g_object_unref(example); + example = NULL; + + if (elem) + return (SbuildChroot *) elem->data; + else + return NULL; +} + +static gint +chroot_findfunc (SbuildChroot *a, + SbuildChroot *b) +{ + return strcmp(sbuild_chroot_get_name(a), + sbuild_chroot_get_name(b)); +} + + +SbuildChroot * +sbuild_config_find_chroot (SbuildConfig *config, + const char *name) +{ + g_return_val_if_fail(SBUILD_IS_CONFIG(config), NULL); + + return sbuild_config_find_generic(config, name, (GCompareFunc) chroot_findfunc); +} + +static gint +alias_findfunc (SbuildChroot *a, + SbuildChroot *b) +{ + gchar **aliases = sbuild_chroot_get_aliases(a); + for (guint i = 0; aliases[i] != NULL; ++i) + { + if (strcmp(aliases[i], sbuild_chroot_get_name(b)) == 0) + return 0; + } + return 1; +} + + +SbuildChroot * +sbuild_config_find_alias (SbuildConfig *config, + const char *name) +{ + g_return_val_if_fail(SBUILD_IS_CONFIG(config), NULL); + + SbuildChroot *chroot = sbuild_config_find_chroot(config, name); + if (chroot == NULL) + chroot = sbuild_config_find_generic(config, name, (GCompareFunc) alias_findfunc); + return chroot; +} + +static void +sbuild_config_get_chroot_list_foreach (SbuildChroot *chroot, + GList **list) +{ + *list = g_list_append(*list, (gpointer) sbuild_chroot_get_name(chroot)); + + gchar **aliases = sbuild_chroot_get_aliases(chroot); + for (guint i = 0; aliases[i] != NULL; ++i) + *list = g_list_append(*list, aliases[i]); +} + +GList * +sbuild_config_get_chroot_list (SbuildConfig *config) +{ + g_return_val_if_fail(SBUILD_IS_CONFIG(config), NULL); + + GList *list = NULL; + + g_list_foreach(config->chroots, (GFunc) sbuild_config_get_chroot_list_foreach, &list); + list = g_list_sort(list, (GCompareFunc) strcmp); + + return list; +} + +static void +sbuild_config_print_chroot_list_foreach (const char *name, + FILE *file) +{ + g_print("%s\n", name); +} + +void +sbuild_config_print_chroot_list (SbuildConfig *config, + FILE *file) +{ + GList *list = sbuild_config_get_chroot_list(config); + g_list_foreach(list, (GFunc) sbuild_config_print_chroot_list_foreach, file); + g_list_free(list); +} + +gboolean +sbuild_config_validate_chroots(SbuildConfig *config, + char **chroots) +{ + gboolean success = TRUE; + for (guint i=0; chroots[i] != NULL; ++i) + { + SbuildChroot *chroot = sbuild_config_find_alias(config, chroots[i]); + if (chroot == NULL) + { + g_printerr("%s: No such chroot\n", chroots[i]); + success = FALSE; + } + } + return success; +} + +static void +sbuild_config_init (SbuildConfig *config) +{ + g_return_if_fail(SBUILD_IS_CONFIG(config)); + + config->file = NULL; + config->chroots = NULL; +} + +static void +sbuild_config_finalize (SbuildConfig *config) +{ + g_return_if_fail(SBUILD_IS_CONFIG(config)); + + if (config->file) + { + g_free (config->file); + config->file = NULL; + } + if (config->chroots) + { + g_list_foreach(config->chroots, (GFunc) g_object_unref, NULL); + g_list_free(config->chroots); + } + + if (parent_class->finalize) + parent_class->finalize(G_OBJECT(config)); +} + +static void +sbuild_config_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + SbuildConfig *config; + + g_return_if_fail (object != NULL); + g_return_if_fail (SBUILD_IS_CONFIG (object)); + + config = SBUILD_CONFIG(object); + + switch (param_id) + { + case PROP_CONFIG_FILE: + sbuild_config_set_config_file(config, g_value_get_string(value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +sbuild_config_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + SbuildConfig *config; + + g_return_if_fail (object != NULL); + g_return_if_fail (SBUILD_IS_CONFIG (object)); + + config = SBUILD_CONFIG(object); + + switch (param_id) + { + case PROP_CONFIG_FILE: + g_value_set_string(value, config->file); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +sbuild_config_class_init (SbuildConfigClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + parent_class = g_type_class_peek_parent (klass); + + /* Override the virtual finalize, set_property and + get_property methods in the GObject class vtable (which + is contained in CseCanvasClass). */ + gobject_class->finalize = (GObjectFinalizeFunc) sbuild_config_finalize; + gobject_class->set_property = (GObjectSetPropertyFunc) sbuild_config_set_property; + gobject_class->get_property = (GObjectGetPropertyFunc) sbuild_config_get_property; + + g_object_class_install_property + (gobject_class, + PROP_CONFIG_FILE, + g_param_spec_string ("config-file", "Configuration File", + "The file containing the chroot configuration", + "", + (G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY))); +} + +/* + * Local Variables: + * mode:C + * End: + */ diff --git a/schroot/sbuild-config.h b/schroot/sbuild-config.h new file mode 100644 index 00000000..87810660 --- /dev/null +++ b/schroot/sbuild-config.h @@ -0,0 +1,97 @@ +/* sbuild-config - sbuild config object + * + * Copyright (C) 2005 Roger Leigh <rleigh@debian.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + *********************************************************************/ + +#ifndef SBUILD_CONFIG_H +#define SBUILD_CONFIG_H + +#include <glib.h> +#include <glib/gprintf.h> +#include <glib-object.h> + +#include "sbuild-chroot.h" + +typedef enum +{ + SBUILD_CONFIG_FILE_ERROR_STAT_FAIL, + SBUILD_CONFIG_FILE_ERROR_OWNERSHIP, + SBUILD_CONFIG_FILE_ERROR_PERMISSIONS, + SBUILD_CONFIG_FILE_ERROR_NOT_REGULAR +} SbuildConfigFileError; + +#define SBUILD_CONFIG_FILE_ERROR sbuild_config_file_error_quark() + +#define SBUILD_TYPE_CONFIG (sbuild_config_get_type ()) +#define SBUILD_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SBUILD_TYPE_CONFIG, SbuildConfig)) +#define SBUILD_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SBUILD_TYPE_CONFIG, SbuildConfigClass)) +#define SBUILD_IS_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SBUILD_TYPE_CONFIG)) +#define SBUILD_IS_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SBUILD_TYPE_CONFIG)) +#define SBUILD_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SBUILD_TYPE_CONFIG, SbuildConfigClass)) + +typedef struct _SbuildConfig SbuildConfig; +typedef struct _SbuildConfigClass SbuildConfigClass; + +struct _SbuildConfig +{ + GObject parent; + char *file; + GList *chroots; +}; + +struct _SbuildConfigClass +{ + GObjectClass parent; +}; + + +GType +sbuild_config_get_type (void); + +SbuildConfig * +sbuild_config_new (const char *file); + +const GList * +sbuild_config_get_chroots (SbuildConfig *config); + +SbuildChroot * +sbuild_config_find_chroot (SbuildConfig *config, + const char *name); + +SbuildChroot * +sbuild_config_find_alias (SbuildConfig *config, + const char *name); + +GList * +sbuild_config_get_chroot_list (SbuildConfig *config); + +void +sbuild_config_print_chroot_list (SbuildConfig *config, + FILE *file); + +gboolean +sbuild_config_validate_chroots(SbuildConfig *config, + char **chroots); + +#endif /* SBUILD_CONFIG_H */ + +/* + * Local Variables: + * mode:C + * End: + */ diff --git a/schroot/sbuild-session.c b/schroot/sbuild-session.c new file mode 100644 index 00000000..853e6498 --- /dev/null +++ b/schroot/sbuild-session.c @@ -0,0 +1,743 @@ +/* sbuild-session - sbuild session object + * + * Copyright (C) 2005 Roger Leigh <rleigh@debian.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + *********************************************************************/ + +/** + * SECTION:sbuild-session + * @short_description: session object + * @title: SbuildSession + * + */ + +#define _GNU_SOURCE 1 +#include <errno.h> +#include <stdlib.h> + +#include <sys/types.h> +#include <sys/wait.h> +#include <grp.h> +#include <pwd.h> +#include <unistd.h> + +#include "sbuild-session.h" + +enum +{ + PROP_0, + PROP_USER, + PROP_COMMAND, + PROP_CONFIG, + PROP_CHROOTS +}; + +static GObjectClass *parent_class; + +G_DEFINE_TYPE(SbuildSession, sbuild_session, G_TYPE_OBJECT) + +static const struct pam_conv sbuild_session_pam_conv = { + misc_conv, + NULL +}; + +/** + * sbuild_session_new: + * + * Creates a new #SbuildSession. + * + * Returns the newly created #SbuildSession. + */ +SbuildSession * +sbuild_session_new(SbuildConfig *config, + char **chroots) +{ + return (SbuildSession *) g_object_new(SBUILD_TYPE_SESSION, + "config", config, + "chroots", chroots, + NULL); +} + +const char * +sbuild_session_get_user (const SbuildSession *restrict session) +{ + g_return_val_if_fail(SBUILD_IS_SESSION(session), NULL); + + return session->user; +} + +void +sbuild_session_set_user (SbuildSession *session, + const char *user) +{ + g_return_if_fail(SBUILD_IS_SESSION(session)); + + if (session->user) + { + g_free(session->user); + } + session->user = g_strdup(user); + if (session->shell) + { + g_free(session->shell); + session->shell = NULL; + } + + if (user != NULL) + { + struct passwd *pwent = getpwnam(session->user); + if (pwent == NULL) + { + g_printerr("%s: user not found: %s\n", session->user, g_strerror(errno)); + exit (EXIT_FAILURE); + } + session->uid = pwent->pw_uid; + session->gid = pwent->pw_gid; + session->shell = g_strdup(pwent->pw_shell); + g_debug("session uid = %lu, gid = %lu\n", (unsigned long) session->uid, + (unsigned long) session->gid); + } + else + { + session->uid = 0; + session->gid = 0; + session->shell = g_strdup("/bin/false"); + } + + g_object_notify(G_OBJECT(session), "user"); +} + +char ** +sbuild_session_get_command (const SbuildSession *restrict session) +{ + g_return_val_if_fail(SBUILD_IS_SESSION(session), NULL); + + return session->command; +} + +void +sbuild_session_set_command (SbuildSession *session, + char **command) +{ + g_return_if_fail(SBUILD_IS_SESSION(session)); + + if (session->command) + { + g_strfreev(session->command); + } + session->command = g_strdupv(command); + g_object_notify(G_OBJECT(session), "command"); +} + +SbuildConfig * +sbuild_session_get_config (const SbuildSession *restrict session) +{ + g_return_val_if_fail(SBUILD_IS_SESSION(session), NULL); + + return session->config; +} + +void +sbuild_session_set_config (SbuildSession *session, + SbuildConfig *config) +{ + g_return_if_fail(SBUILD_IS_SESSION(session)); + + if (session->config) + { + g_object_unref(G_OBJECT(session->config)); + } + session->config = config; + g_object_ref(G_OBJECT(session->config)); + g_object_notify(G_OBJECT(session), "config"); +} + +char ** +sbuild_session_get_chroots (const SbuildSession *restrict session) +{ + g_return_val_if_fail(SBUILD_IS_SESSION(session), NULL); + + return session->chroots; +} + +void +sbuild_session_set_chroots (SbuildSession *session, + char **chroots) +{ + g_return_if_fail(SBUILD_IS_SESSION(session)); + + if (session->chroots) + { + g_strfreev(session->chroots); + } + session->chroots = g_strdupv(chroots); + g_object_notify(G_OBJECT(session), "chroots"); +} + +/* Run command in chroot */ +static int +sbuild_session_run_chroot (SbuildSession *session, + SbuildChroot *session_chroot) +{ + g_return_val_if_fail(SBUILD_IS_SESSION(session), -1); + g_return_val_if_fail(SBUILD_IS_CHROOT(session_chroot), -1); + + g_assert(session->user != NULL); + g_assert(session->shell != NULL); + + pid_t pid; + if ((pid = fork()) == -1) + { + fprintf (stderr, "Could not fork child: %s\n", g_strerror(errno)); + exit (EXIT_FAILURE); + } + else if (pid == 0) + { + const char *location = sbuild_chroot_get_location(session_chroot); + char *cwd = g_get_current_dir(); + + /* Set group ID and supplementary groups */ + if (setgid (session->gid)) + { + fprintf (stderr, "Could not set gid to %lu\n", (unsigned long) session->gid); + exit (EXIT_FAILURE); + } + if (initgroups (session->user, session->gid)) + { + fprintf (stderr, "Could not set supplementary group IDs\n"); + exit (EXIT_FAILURE); + } + + /* Enter the chroot */ + if (chdir (location)) + { + fprintf (stderr, "Could not chdir to %s: %s\n", location, + g_strerror (errno)); + exit (EXIT_FAILURE); + } + if (chroot (location)) + { + fprintf (stderr, "Could not chroot to %s: %s\n", location, + g_strerror (errno)); + exit (EXIT_FAILURE); + } + /* printf ("Entered chroot: %s\n", location); */ + + /* Set uid and check we are not still root */ + if (setuid (session->uid)) + { + fprintf (stderr, "Could not set uid to %lu\n", (unsigned long) session->uid); + exit (EXIT_FAILURE); + } + if (!setuid (0) && session->uid) + { + fprintf (stderr, "Failed to drop root permissions.\n"); + exit (EXIT_FAILURE); + } + + /* Set up environment */ +/* if (pass->pw_dir) */ +/* setenv("HOME", pass->pw_dir, 1); */ +/* else */ +/* setenv("HOME", "/", 1); */ + + /* chdir to current directory */ + if (chdir (cwd)) + { + fprintf (stderr, "warning: Could not chdir to %s: %s\n", cwd, + g_strerror (errno)); + } + g_free(cwd); + + char **env = pam_getenvlist(session->pam); + // Can this fail? + g_assert (env != NULL); + + /* Run login shell */ + if ((session->command == NULL || + session->command[0] == NULL)) // No command + { + g_assert (session->shell != NULL); + + session->command = g_new(char *, 2); + session->command[0] = g_strdup(session->shell); + session->command[1] = NULL; + + g_debug("Running login shell: %s", session->shell); + } + else + g_debug("Running command: %s", session->command[0]); + + /* Execute */ + if (execve (session->command[0], session->command, env)) + { + fprintf (stderr, "Could not exec %s: %s\n", session->command[0], + g_strerror (errno)); + exit (EXIT_FAILURE); + } + /* This should never be reached */ + exit(EXIT_FAILURE); + } + else + { + int status; + if (wait(&status) != pid) + { + fprintf (stderr, "wait for child failed: %s\n", g_strerror (errno)); + exit (EXIT_FAILURE); + } + + if (!WIFEXITED(status)) + { + g_print("Child exited abnormally\n"); + return -1; + } + + if (WEXITSTATUS(status)) + { + g_print("Child exited abnormally\n"); + } + + return WEXITSTATUS(status); + } +} + +/* Check group membership */ +static gboolean +is_group_member (const char *group) +{ + errno = 0; + struct group *groupbuf = getgrnam(group); + if (groupbuf == NULL) + { + if (errno == 0) + g_printerr("%s: group not found\n", group); + else + g_printerr("%s: group not found: %s\n", group, g_strerror(errno)); + exit (EXIT_FAILURE); + } + + int supp_group_count = getgroups(0, NULL); + if (supp_group_count < 0) + { + g_printerr("can't get supplementary group count: %s\n", g_strerror(errno)); + exit (EXIT_FAILURE); + } + gid_t supp_groups[supp_group_count]; + if (getgroups(supp_group_count, supp_groups) < 1) + { + g_printerr("can't get supplementary groups: %s\n", g_strerror(errno)); + exit (EXIT_FAILURE); + } + + gboolean group_member = FALSE; + + for (int i = 0; i < supp_group_count; ++i) + { + if (groupbuf->gr_gid == supp_groups[i]) + group_member = TRUE; + } + + return group_member; +} + +typedef enum +{ + SBUILD_SESSION_AUTH_NONE, + SBUILD_SESSION_AUTH_USER, + SBUILD_SESSION_AUTH_FAIL +} SbuildSessionAuthType; + +static inline SbuildSessionAuthType +set_auth (SbuildSessionAuthType oldauth, + SbuildSessionAuthType newauth) +{ + /* Ensure auth level always escalates. */ + if (newauth > oldauth) + return newauth; + else + return oldauth; +} + +static SbuildSessionAuthType +sbuild_session_require_auth (SbuildSession *session) +{ + g_return_val_if_fail(SBUILD_IS_SESSION(session), SBUILD_SESSION_AUTH_FAIL); + g_return_val_if_fail(session->chroots != NULL, SBUILD_SESSION_AUTH_FAIL); + g_return_val_if_fail(session->user != NULL, SBUILD_SESSION_AUTH_FAIL); + + SbuildSessionAuthType auth = SBUILD_SESSION_AUTH_NONE; + + for (guint i=0; session->chroots[i] != NULL; ++i) + { + SbuildChroot *chroot = sbuild_config_find_alias(session->config, + session->chroots[i]); + if (chroot == NULL) // Should never happen, but cater for it anyway. + { + g_warning("No chroot found matching alias %s", session->chroots[i]); + auth = set_auth(auth, SBUILD_SESSION_AUTH_FAIL); + } + + char **groups = NULL; + if (session->uid == 0) + groups = sbuild_chroot_get_root_groups(chroot); + else + groups = sbuild_chroot_get_groups(chroot); + + if (groups) + { + for (guint y=0; groups[y] != 0; ++y) + { + if (is_group_member(groups[y]) == TRUE) // No auth required + auth = set_auth(auth, SBUILD_SESSION_AUTH_NONE); + else + auth = set_auth(auth, SBUILD_SESSION_AUTH_USER); + } + } + } + + return auth; +} + +void +sbuild_session_run (SbuildSession *session) +{ + /* PAM setup. */ + + int pam_status; + if ((pam_status = + pam_start("schroot", session->user, + &sbuild_session_pam_conv, &session->pam)) != PAM_SUCCESS) + { + g_printerr("PAM initialisation error: %s\n", pam_strerror(session->pam, pam_status)); + exit (EXIT_FAILURE); + } + + if ((pam_status = + pam_set_item(session->pam, PAM_RUSER, session->ruser)) != PAM_SUCCESS) + { + g_printerr("PAM set RUSER failed: %s\n", pam_strerror(session->pam, pam_status)); + exit (EXIT_FAILURE); + } + + + long hl = 256; /* BROKEN with libc6 sysconf(_SC_HOST_NAME_MAX); */ + + char *hostname = g_new(char, hl); + if (gethostname(hostname, hl) != 0) + { + g_printerr("failed to get hostname: %s\n", g_strerror(errno)); + exit (EXIT_FAILURE); + } + + if ((pam_status = + pam_set_item(session->pam, PAM_RHOST, hostname)) != PAM_SUCCESS) + { + g_printerr("PAM set RHOST failed: %s\n", pam_strerror(session->pam, pam_status)); + exit (EXIT_FAILURE); + } + + g_free(hostname); + hostname = NULL; + + const char *tty = ttyname(STDIN_FILENO); + if (tty) + { + if ((pam_status = + pam_set_item(session->pam, PAM_TTY, tty)) != PAM_SUCCESS) + { + g_printerr("PAM set TTY failed: %s\n", pam_strerror(session->pam, pam_status)); + exit (EXIT_FAILURE); + } + } + + /* Authenticate as required. */ + switch (sbuild_session_require_auth (session)) + { + case SBUILD_SESSION_AUTH_NONE: + if ((pam_status = + pam_set_item(session->pam, PAM_USER, session->user)) != PAM_SUCCESS) + { + g_printerr("PAM set USER failed: %s\n", pam_strerror(session->pam, pam_status)); + exit (EXIT_FAILURE); + } + break; + + case SBUILD_SESSION_AUTH_USER: + if ((pam_status = + pam_authenticate(session->pam, 0)) != PAM_SUCCESS) + { + g_printerr("PAM authentication failed: %s\n", pam_strerror(session->pam, pam_status)); + exit (EXIT_FAILURE); + } + break; + + case SBUILD_SESSION_AUTH_FAIL: + g_printerr("PAM authentication failed prematurely due to configuration error\n"); + exit (EXIT_FAILURE); + default: + break; + } + + if ((pam_status = + pam_acct_mgmt(session->pam, 0)) != PAM_SUCCESS) + { + /* We don't handle changing expired passwords here, since we are + not login or ssh. */ + g_printerr("PAM account management failed: %s\n", + pam_strerror(session->pam, pam_status)); + exit (EXIT_FAILURE); + } + + if ((pam_status = + pam_setcred(session->pam, PAM_ESTABLISH_CRED)) != PAM_SUCCESS) + { + /* We don't handle changing expired passwords here, since we are + not login or ssh. */ + g_printerr("PAM user credentials setup failed: %s\n", + pam_strerror(session->pam, pam_status)); + exit (EXIT_FAILURE); + } + + if ((pam_status = + pam_open_session(session->pam, 0)) != PAM_SUCCESS) + { + g_printerr("PAM open session failed: %s\n", + pam_strerror(session->pam, pam_status)); + exit (EXIT_FAILURE); + } + + const char *authuser = NULL; + pam_get_item(session->pam, PAM_USER, (const void **) &authuser); + g_printerr("PAM authentication succeeded for user %s\n", authuser); + + for (guint x=0; session->chroots[x] != 0; ++x) + { + g_printerr("Running session in %s chroot:\n", session->chroots[x]); + SbuildChroot *chroot = sbuild_config_find_alias(session->config, + session->chroots[x]); + sbuild_session_run_chroot(session, chroot); + } + + if ((pam_status = + pam_close_session(session->pam, 0)) != PAM_SUCCESS) + { + g_printerr("PAM close session failed: %s\n", + pam_strerror(session->pam, pam_status)); + exit (EXIT_FAILURE); + } + + if ((pam_status = + pam_setcred(session->pam, PAM_DELETE_CRED)) != PAM_SUCCESS) + { + g_printerr("PAM user credentials deletion failed: %s\n", + pam_strerror(session->pam, pam_status)); + exit (EXIT_FAILURE); + } + + if ((pam_status = + pam_end(session->pam, PAM_SUCCESS)) != PAM_SUCCESS) + { + g_printerr("PAM finalisation failed: %s\n", + pam_strerror(session->pam, pam_status)); + exit (EXIT_FAILURE); + } +} + +static void +sbuild_session_init (SbuildSession *session) +{ + g_return_if_fail(SBUILD_IS_SESSION(session)); + + session->user = NULL; + session->uid = 0; + session->gid = 0; + session->command = NULL; + session->shell = NULL; + session->config = NULL; + session->chroots = NULL; + session->pam = NULL; + + /* Current user's details. */ + session->ruid = getuid(); + struct passwd *pwent = getpwuid(session->ruid); + if (pwent == NULL) + { + g_printerr("%lu: user not found: %s\n", (unsigned long) session->ruid, + g_strerror(errno)); + exit (EXIT_FAILURE); + } + session->ruser = g_strdup(pwent->pw_name); + + /* By default, the session user is the same as the remote user. */ + sbuild_session_set_user(session, session->ruser); +} + +static void +sbuild_session_finalize (SbuildSession *session) +{ + g_return_if_fail(SBUILD_IS_SESSION(session)); + + if (session->user) + { + g_free (session->user); + session->user = NULL; + } + if (session->command) + { + g_strfreev (session->command); + session->command = NULL; + } + if (session->shell) + { + g_free (session->shell); + session->shell = NULL; + } + if (session->ruser) + { + g_free (session->ruser); + session->ruser = NULL; + } + if (session->config) + { + g_object_unref (session->config); + session->config = NULL; + } + if (session->chroots) + { + g_strfreev(session->chroots); + session->chroots = NULL; + } + + if (parent_class->finalize) + parent_class->finalize(G_OBJECT(session)); +} + +static void +sbuild_session_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + SbuildSession *session; + + g_return_if_fail (object != NULL); + g_return_if_fail (SBUILD_IS_SESSION (object)); + + session = SBUILD_SESSION(object); + + switch (param_id) + { + case PROP_USER: + sbuild_session_set_user(session, g_value_get_string(value)); + break; + case PROP_COMMAND: + sbuild_session_set_command(session, g_value_get_boxed(value)); + break; + case PROP_CONFIG: + sbuild_session_set_config(session, g_value_get_object(value)); + break; + case PROP_CHROOTS: + sbuild_session_set_chroots(session, g_value_get_boxed(value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +sbuild_session_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + SbuildSession *session; + + g_return_if_fail (object != NULL); + g_return_if_fail (SBUILD_IS_SESSION (object)); + + session = SBUILD_SESSION(object); + + switch (param_id) + { + case PROP_USER: + g_value_set_string(value, session->user); + break; + case PROP_COMMAND: + g_value_set_boxed(value, session->command); + break; + case PROP_CONFIG: + g_value_set_object(value, session->config); + break; + case PROP_CHROOTS: + g_value_set_boxed(value, session->chroots); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +sbuild_session_class_init (SbuildSessionClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + parent_class = g_type_class_peek_parent (klass); + + gobject_class->finalize = (GObjectFinalizeFunc) sbuild_session_finalize; + gobject_class->set_property = (GObjectSetPropertyFunc) sbuild_session_set_property; + gobject_class->get_property = (GObjectGetPropertyFunc) sbuild_session_get_property; + + g_object_class_install_property + (gobject_class, + PROP_USER, + g_param_spec_string ("user", "User", + "The user to run as in the chroot", + "", + (G_PARAM_READABLE | G_PARAM_WRITABLE))); + + g_object_class_install_property + (gobject_class, + PROP_COMMAND, + g_param_spec_boxed ("command", "Command", + "The command to run in the chroot, or NULL for a login shell", + G_TYPE_STRV, + (G_PARAM_READABLE | G_PARAM_WRITABLE))); + + g_object_class_install_property + (gobject_class, + PROP_CONFIG, + g_param_spec_object ("config", "Configuration", + "The chroot configuration data", + SBUILD_TYPE_CONFIG, + (G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT))); + + g_object_class_install_property + (gobject_class, + PROP_CHROOTS, + g_param_spec_boxed ("chroots", "Chroots", + "The chroots to use", + G_TYPE_STRV, + (G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT))); +} + +/* + * Local Variables: + * mode:C + * End: + */ diff --git a/schroot/sbuild-session.h b/schroot/sbuild-session.h new file mode 100644 index 00000000..1497e2c9 --- /dev/null +++ b/schroot/sbuild-session.h @@ -0,0 +1,108 @@ +/* sbuild-session - sbuild session object + * + * Copyright (C) 2005 Roger Leigh <rleigh@debian.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + *********************************************************************/ + +#ifndef SBUILD_SESSION_H +#define SBUILD_SESSION_H + +#include <security/pam_appl.h> +#include <security/pam_misc.h> + +#include <glib.h> +#include <glib/gprintf.h> +#include <glib-object.h> + +#include "sbuild-config.h" + +#define SBUILD_TYPE_SESSION (sbuild_session_get_type ()) +#define SBUILD_SESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SBUILD_TYPE_SESSION, SbuildSession)) +#define SBUILD_SESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SBUILD_TYPE_SESSION, SbuildSessionClass)) +#define SBUILD_IS_SESSION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SBUILD_TYPE_SESSION)) +#define SBUILD_IS_SESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SBUILD_TYPE_SESSION)) +#define SBUILD_SESSION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SBUILD_TYPE_SESSION, SbuildSessionClass)) + +typedef struct _SbuildSession SbuildSession; +typedef struct _SbuildSessionClass SbuildSessionClass; + +struct _SbuildSession +{ + GObject parent; + uid_t uid; + gid_t gid; + gchar *user; + gchar **command; + gchar *shell; + uid_t ruid; + gchar *ruser; + SbuildConfig *config; + char **chroots; + pam_handle_t *pam; +}; + +struct _SbuildSessionClass +{ + GObjectClass parent; +}; + + +GType +sbuild_session_get_type (void); + +SbuildSession * +sbuild_session_new(SbuildConfig *config, + char **chroots); + +const char * +sbuild_session_get_user (const SbuildSession *restrict session); + +void +sbuild_session_set_user (SbuildSession *session, + const char *user); + +char ** +sbuild_session_get_command (const SbuildSession *restrict session); + +void +sbuild_session_set_command (SbuildSession *session, + char **command); + +SbuildConfig * +sbuild_session_get_config (const SbuildSession *restrict session); + +void +sbuild_session_set_config (SbuildSession *session, + SbuildConfig *config); + +char ** +sbuild_session_get_chroots (const SbuildSession *restrict session); + +void +sbuild_session_set_chroots (SbuildSession *session, + char **chroots); + +void +sbuild_session_run (SbuildSession *session); + +#endif /* SBUILD_SESSION_H */ + +/* + * Local Variables: + * mode:C + * End: + */ diff --git a/schroot/schroot.c b/schroot/schroot.c new file mode 100644 index 00000000..922f17a6 --- /dev/null +++ b/schroot/schroot.c @@ -0,0 +1,163 @@ +/* schroot - securely enter a chroot + * + * Copyright (C) 2005 Roger Leigh <rleigh@debian.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + *********************************************************************/ + +#define _GNU_SOURCE +#include <stdlib.h> +#include <stdio.h> + +#include <syslog.h> + +#include <glib.h> + +#include "sbuild-chroot.h" +#include "sbuild-config.h" +#include "sbuild-session.h" + +static struct { + const char **chroots; + const char **command; + const char *user; + gboolean preserve; + gboolean quiet; + gboolean list; + gboolean info; + gboolean all; +} opt = + { + .chroots = NULL, + .command = NULL, + .user = NULL, + .preserve = FALSE, + .quiet = FALSE, + .list = FALSE, + .info = FALSE, + .all = FALSE + }; + +static GOptionEntry entries[] = +{ + { "all", 'a', 0, G_OPTION_ARG_NONE, &opt.all, "Run command in all chroots", NULL }, + { "chroot", 'c', 0, G_OPTION_ARG_STRING_ARRAY, &opt.chroots, "Use specified chroot", "chroot" }, + { "user", 'u', 0, G_OPTION_ARG_STRING, &opt.user, "Username (default current user)", "user" }, + { "list", 'l', 0, G_OPTION_ARG_NONE, &opt.list, "List available chroots", NULL }, + { "info", 'i', 0, G_OPTION_ARG_NONE, &opt.info, "Show information about chroot", NULL }, + { "preserve-environment", 'p', 0, G_OPTION_ARG_NONE, &opt.preserve, "Preserve user environment", NULL }, + { "quiet", 'q', 0, G_OPTION_ARG_NONE, &opt.quiet, "Show less output", NULL }, + { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt.command, NULL, NULL } +}; + +static void +parse_options(int argc, + char *argv[]) +{ + GError *error = NULL; + + GOptionContext *context = g_option_context_new ("- run command or shell in a chroot"); + g_option_context_add_main_entries (context, entries, NULL); + g_option_context_parse (context, &argc, &argv, &error); +} + +char ** +get_chroot_options(SbuildConfig *config) +{ + char **chroots = NULL; + + if (opt.all == TRUE) + { + const GList *list = sbuild_config_get_chroots(config); + guint num_chroots = g_list_length(list); + chroots = g_new(char *, num_chroots + 1); + chroots[num_chroots] = NULL; + for (guint i=0; i < num_chroots; ++i) + { + GList *node = g_list_nth(list, i); + g_assert(node != NULL); + SbuildChroot *chroot = node->data; + chroots[i] = g_strdup(sbuild_chroot_get_name(chroot)); + } + } + else if (opt.chroots == NULL) + { + g_printerr("No chroot specified. Use --chroot or --all.\n"); + exit (EXIT_FAILURE); + } + else + { + if (sbuild_config_validate_chroots(config, opt.chroots) == FALSE) + exit(EXIT_FAILURE); + chroots = g_strdupv(opt.chroots); + } + + return chroots; +} + +int +main (int argc, + char *argv[]) +{ + g_type_init(); + + openlog("schroot", LOG_PID, LOG_AUTHPRIV); + + /* Parse command-line options into opt structure. */ + parse_options(argc, argv); + + /* Initialise chroot configuration. */ + SbuildConfig *config = sbuild_config_new("test.conf"); + g_assert (config != NULL); + + /* Print chroot list (including aliases). */ + if (opt.list == TRUE) + { + sbuild_config_print_chroot_list(config, stdout); + exit(EXIT_SUCCESS); + } + + /* Get list of chroots to use */ + char **chroots = get_chroot_options(config); + + /* Print chroot information for specified chroots. */ + if (opt.info == TRUE) + { + for (guint i=0; chroots[i] != NULL; ++i) + { + SbuildChroot *chroot = sbuild_config_find_alias(config, chroots[i]); + if (chroot) + sbuild_chroot_print_details(chroot, stdout); + } + exit (EXIT_SUCCESS); + } + + SbuildSession *session = sbuild_session_new(config, chroots); + if (opt.user) + sbuild_session_set_user(session, opt.user); + if (opt.command) + sbuild_session_set_command(session, opt.command); + + sbuild_session_run(session); + + + g_object_unref(G_OBJECT(session)); + g_object_unref(G_OBJECT(config)); + + closelog(); + + exit (EXIT_SUCCESS); +} diff --git a/schroot/schroot.conf b/schroot/schroot.conf new file mode 100644 index 00000000..cbd84c62 --- /dev/null +++ b/schroot/schroot.conf @@ -0,0 +1,14 @@ +# Sample configuration + +[sid] +description=Debian unstable +location=/srv/chroot/sid +groups=sbuild +root-groups=root +aliases=unstable,default + +[etch] +description=Debian testing +location=/srv/chroot/etch +#groups=sbuild-security +aliases=testing |