Accomodate older glibc, which also lacks the module syscalls
[oweals/busybox.git] / addgroup.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * addgroup - add users to /etc/passwd and /etc/shadow
4  *
5  *
6  * Copyright (C) 1999 by Lineo, inc.
7  * Written by John Beppu <beppu@lineo.com>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22  *
23  */
24
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/param.h>
32 #include <sys/stat.h>
33 #include <sys/types.h>
34 #include <unistd.h>
35 #include "busybox.h"
36 #include "pwd_grp/pwd.h"
37 #include "pwd_grp/grp.h"
38
39 #define GROUP_FILE      "/etc/group"
40 #define SHADOW_FILE             "/etc/gshadow"
41
42
43 /* structs __________________________ */
44
45 /* data _____________________________ */
46
47 /* defaults : should this be in an external file? */
48 static char *default_passwd = "x";
49
50
51 /* make sure gr_name isn't taken, make sure gid is kosher
52  * return 1 on failure */
53 static int group_study(const char *filename, struct group *g)
54 {
55         FILE *etc_group;
56         gid_t desired;
57
58         struct group *grp;
59         const int max = 65000;
60
61         /* FIXME : make an fopen_wrapper */
62         etc_group = fopen(filename, "r");
63         if (!etc_group) {
64                 perror_msg_and_die("%s", filename);
65         }
66
67         /* make sure gr_name isn't taken, make sure gid is kosher */
68         desired = g->gr_gid;
69         while ((grp = fgetgrent(etc_group))) {
70                 if ((strcmp(grp->gr_name, g->gr_name)) == 0) {
71                         error_msg_and_die("%s: group already in use\n", g->gr_name);
72                 }
73                 if ((desired) && grp->gr_gid == desired) {
74                         error_msg_and_die("%d: gid has already been allocated\n",
75                                                           desired);
76                 }
77                 if ((grp->gr_gid > g->gr_gid) && (grp->gr_gid < max)) {
78                         g->gr_gid = grp->gr_gid;
79                 }
80         }
81         fclose(etc_group);
82
83         /* gid */
84         if (desired) {
85                 g->gr_gid = desired;
86         } else {
87                 g->gr_gid++;
88         }
89         /* return 1; */
90         return 0;
91 }
92
93 /* append a new user to the passwd file */
94 static int addgroup(const char *filename, char *group, gid_t gid)
95 {
96         FILE *etc_group;
97         FILE *etc_gshadow;
98         char *gshadow = SHADOW_FILE;
99
100         struct group gr;
101
102         /* group:passwd:gid:userlist */
103         const char *entryfmt = "%s:%s:%d:%s\n";
104
105         /* make sure gid and group haven't already been allocated */
106         gr.gr_gid = gid;
107         gr.gr_name = group;
108         if (group_study(filename, &gr))
109                 return 1;
110
111         /* add entry to group */
112         etc_group = fopen(filename, "a");
113         if (!etc_group) {
114                 perror_msg_and_die("%s", filename);
115         }
116         fprintf(etc_group, entryfmt, group, default_passwd, gr.gr_gid, "");
117         fclose(etc_group);
118
119         /* add entry to gshadow if necessary */
120         if (access(gshadow, F_OK|W_OK) == 0) {
121                 etc_gshadow = xfopen(gshadow, "a");
122                 fprintf(etc_gshadow, "%s:!::\n", group);
123                 fclose(etc_gshadow);
124         }
125
126         /* return 1; */
127         return 0;
128 }
129
130 /*
131  * addgroup will take a login_name as its first parameter.
132  *
133  * gid 
134  *
135  * can be customized via command-line parameters.
136  * ________________________________________________________________________ */
137 int addgroup_main(int argc, char **argv)
138 {
139         int i;
140         char opt;
141         char *group;
142         gid_t gid = 0;
143
144         /* get remaining args */
145         for (i = 1; i < argc; i++) {
146                 if (argv[i][0] == '-') {
147                         opt = argv[i][1];
148                         switch (opt) {
149                         case 'h':
150                                 show_usage();
151                                 break;
152                         case 'g':
153                                 gid = strtol(argv[++i], NULL, 10);
154                                 break;
155                         default:
156                                 error_msg_and_die("addgroup: invalid option -- %c\n", opt);
157                         }
158                 } else {
159                         break;
160                 }
161         }
162
163         if (i >= argc) {
164                 show_usage();
165         } else {
166                 group = argv[i];
167         }
168
169         if (geteuid() != 0) {
170                 error_msg_and_die
171                         ("addgroup: Only root may add a group to the system.\n");
172         }
173
174         /* werk */
175         return addgroup(GROUP_FILE, group, gid);
176 }
177
178 /* $Id: addgroup.c,v 1.1 2001/08/21 16:18:59 andersen Exp $ */