Magellan Linux

Diff of /trunk/mkinitrd-magellan/busybox/loginutils/adduser.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 983 by niro, Fri Apr 24 18:33:46 2009 UTC revision 984 by niro, Sun May 30 11:32:42 2010 UTC
# Line 7  Line 7 
7   *   *
8   * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.   * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
9   */   */
   
10  #include "libbb.h"  #include "libbb.h"
11    
12    #if CONFIG_LAST_SYSTEM_ID < CONFIG_FIRST_SYSTEM_ID
13    #error Bad LAST_SYSTEM_ID or FIRST_SYSTEM_ID in .config
14    #endif
15    
16    /* #define OPT_HOME           (1 << 0) */ /* unused */
17    /* #define OPT_GECOS          (1 << 1) */ /* unused */
18    #define OPT_SHELL          (1 << 2)
19    #define OPT_GID            (1 << 3)
20  #define OPT_DONT_SET_PASS  (1 << 4)  #define OPT_DONT_SET_PASS  (1 << 4)
21  #define OPT_SYSTEM_ACCOUNT (1 << 5)  #define OPT_SYSTEM_ACCOUNT (1 << 5)
22  #define OPT_DONT_MAKE_HOME (1 << 6)  #define OPT_DONT_MAKE_HOME (1 << 6)
23    #define OPT_UID            (1 << 7)
24    
25    /* We assume UID_T_MAX == INT_MAX */
26  /* remix */  /* remix */
27  /* recoded such that the uid may be passed in *p */  /* recoded such that the uid may be passed in *p */
28  static void passwd_study(struct passwd *p)  static void passwd_study(struct passwd *p)
29  {  {
30   int max;   int max = UINT_MAX;
   
  if (getpwnam(p->pw_name))  
  bb_error_msg_and_die("login '%s' is in use", p->pw_name);  
31    
32   if (option_mask32 & OPT_SYSTEM_ACCOUNT) {   if (getpwnam(p->pw_name)) {
33   p->pw_uid = 0;   bb_error_msg_and_die("%s '%s' in use", "user", p->pw_name);
34   max = 999;   /* this format string is reused in adduser and addgroup */
  } else {  
  p->pw_uid = 1000;  
  max = 64999;  
35   }   }
36    
37     if (!(option_mask32 & OPT_UID)) {
38     if (option_mask32 & OPT_SYSTEM_ACCOUNT) {
39     p->pw_uid = CONFIG_FIRST_SYSTEM_ID;
40     max = CONFIG_LAST_SYSTEM_ID;
41     } else {
42     p->pw_uid = CONFIG_LAST_SYSTEM_ID + 1;
43     max = 64999;
44     }
45     }
46   /* check for a free uid (and maybe gid) */   /* check for a free uid (and maybe gid) */
47   while (getpwuid(p->pw_uid) || (!p->pw_gid && getgrgid(p->pw_uid)))   while (getpwuid(p->pw_uid) || (p->pw_gid == (gid_t)-1 && getgrgid(p->pw_uid))) {
48     if (option_mask32 & OPT_UID) {
49     /* -u N, cannot pick uid other than N: error */
50     bb_error_msg_and_die("%s '%s' in use", "uid", itoa(p->pw_uid));
51     /* this format string is reused in adduser and addgroup */
52     }
53     if (p->pw_uid == max) {
54     bb_error_msg_and_die("no %cids left", 'u');
55     }
56   p->pw_uid++;   p->pw_uid++;
   
  if (!p->pw_gid) {  
  /* new gid = uid */  
  p->pw_gid = p->pw_uid;  
  if (getgrnam(p->pw_name))  
  bb_error_msg_and_die("group name '%s' is in use", p->pw_name);  
57   }   }
58    
59   if (p->pw_uid > max)   if (p->pw_gid == (gid_t)-1) {
60   bb_error_msg_and_die("no free uids left");   p->pw_gid = p->pw_uid; /* new gid = uid */
61     if (getgrnam(p->pw_name)) {
62     bb_error_msg_and_die("%s '%s' in use", "group", p->pw_name);
63     /* this format string is reused in adduser and addgroup */
64     }
65     }
66  }  }
67    
68  static void addgroup_wrapper(struct passwd *p)  static void addgroup_wrapper(struct passwd *p, const char *group_name)
69  {  {
70   char *cmd;   char *cmd;
71    
72   cmd = xasprintf("addgroup -g %u '%s'", (unsigned)p->pw_gid, p->pw_name);   if (group_name) /* Add user to existing group */
73     cmd = xasprintf("addgroup '%s' '%s'", p->pw_name, group_name);
74     else    /* Add user to his own group with the first free gid found in passwd_study */
75     cmd = xasprintf("addgroup -g %u '%s'", (unsigned)p->pw_gid, p->pw_name);
76     /* Warning: to be compatible with external addgroup programs we should use --gid instead */
77   system(cmd);   system(cmd);
78   free(cmd);   free(cmd);
79  }  }
# Line 60  static void passwd_wrapper(const char *l Line 82  static void passwd_wrapper(const char *l
82    
83  static void passwd_wrapper(const char *login)  static void passwd_wrapper(const char *login)
84  {  {
85   static const char prog[] ALIGN1 = "passwd";   BB_EXECLP("passwd", "passwd", login, NULL);
86     bb_error_msg_and_die("can't execute passwd, you must set password manually");
  BB_EXECLP(prog, prog, login, NULL);  
  bb_error_msg_and_die("cannot execute %s, you must set password manually", prog);  
87  }  }
88    
89  #if ENABLE_FEATURE_ADDUSER_LONG_OPTIONS  #if ENABLE_FEATURE_ADDUSER_LONG_OPTIONS
# Line 76  static const char adduser_longopts[] ALI Line 96  static const char adduser_longopts[] ALI
96   "empty-password\0"      No_argument       "D"   "empty-password\0"      No_argument       "D"
97   "system\0"              No_argument       "S"   "system\0"              No_argument       "S"
98   "no-create-home\0"      No_argument       "H"   "no-create-home\0"      No_argument       "H"
99     "uid\0"                 Required_argument "u"
100   ;   ;
101  #endif  #endif
102    
# Line 89  int adduser_main(int argc UNUSED_PARAM, Line 110  int adduser_main(int argc UNUSED_PARAM,
110  {  {
111   struct passwd pw;   struct passwd pw;
112   const char *usegroup = NULL;   const char *usegroup = NULL;
113   FILE *file;   char *p;
114     unsigned opts;
115    
116  #if ENABLE_FEATURE_ADDUSER_LONG_OPTIONS  #if ENABLE_FEATURE_ADDUSER_LONG_OPTIONS
117   applet_long_options = adduser_longopts;   applet_long_options = adduser_longopts;
# Line 105  int adduser_main(int argc UNUSED_PARAM, Line 127  int adduser_main(int argc UNUSED_PARAM,
127   pw.pw_dir = NULL;   pw.pw_dir = NULL;
128    
129   /* exactly one non-option arg */   /* exactly one non-option arg */
130   opt_complementary = "=1";   /* disable interactive passwd for system accounts */
131   getopt32(argv, "h:g:s:G:DSH", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup);   opt_complementary = "=1:SD:u+";
132     if (sizeof(pw.pw_uid) == sizeof(int)) {
133     opts = getopt32(argv, "h:g:s:G:DSHu:", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup, &pw.pw_uid);
134     } else {
135     unsigned uid;
136     opts = getopt32(argv, "h:g:s:G:DSHu:", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup, &uid);
137     if (opts & OPT_UID) {
138     pw.pw_uid = uid;
139     }
140     }
141   argv += optind;   argv += optind;
142    
143   /* fill in the passwd struct */   /* fill in the passwd struct */
# Line 117  int adduser_main(int argc UNUSED_PARAM, Line 148  int adduser_main(int argc UNUSED_PARAM,
148   pw.pw_dir = xasprintf("/home/%s", argv[0]);   pw.pw_dir = xasprintf("/home/%s", argv[0]);
149   }   }
150   pw.pw_passwd = (char *)"x";   pw.pw_passwd = (char *)"x";
151   pw.pw_gid = usegroup ? xgroup2gid(usegroup) : 0; /* exits on failure */   if (opts & OPT_SYSTEM_ACCOUNT) {
152     if (!usegroup) {
153     usegroup = "nogroup";
154     }
155     if (!(opts & OPT_SHELL)) {
156     pw.pw_shell = (char *) "/bin/false";
157     }
158     }
159     pw.pw_gid = usegroup ? xgroup2gid(usegroup) : -1; /* exits on failure */
160    
161   /* make sure everything is kosher and setup uid && maybe gid */   /* make sure everything is kosher and setup uid && maybe gid */
162   passwd_study(&pw);   passwd_study(&pw);
163    
164   /* add to passwd */   p = xasprintf("x:%u:%u:%s:%s:%s",
165   file = xfopen(bb_path_passwd_file, "a");   (unsigned) pw.pw_uid, (unsigned) pw.pw_gid,
166   //fseek(file, 0, SEEK_END); /* paranoia, "a" should ensure that anyway */   pw.pw_gecos, pw.pw_dir, pw.pw_shell);
167   if (putpwent(&pw, file) != 0) {   if (update_passwd(bb_path_passwd_file, pw.pw_name, p, NULL) < 0) {
168   bb_perror_nomsg_and_die();   return EXIT_FAILURE;
169   }   }
170   /* do fclose even if !ENABLE_FEATURE_CLEAN_UP.   if (ENABLE_FEATURE_CLEAN_UP)
171   * We will exec passwd, files must be flushed & closed before that! */   free(p);
  fclose(file);  
172    
173  #if ENABLE_FEATURE_SHADOWPASSWDS  #if ENABLE_FEATURE_SHADOWPASSWDS
174   /* add to shadow if necessary */   /* /etc/shadow fields:
175   file = fopen_or_warn(bb_path_shadow_file, "a");   * 1. username
176   if (file) {   * 2. encrypted password
177   //fseek(file, 0, SEEK_END);   * 3. last password change (unix date (unix time/24*60*60))
178   fprintf(file, "%s:!:%u:0:99999:7:::\n",   * 4. minimum days required between password changes
179   pw.pw_name,             /* username */   * 5. maximum days password is valid
180   (unsigned)(time(NULL) / 86400) /* sp->sp_lstchg */   * 6. days before password is to expire that user is warned
181   /*0,*/                  /* sp->sp_min */   * 7. days after password expires that account is disabled
182   /*99999,*/              /* sp->sp_max */   * 8. unix date when login expires (i.e. when it may no longer be used)
183   /*7*/                   /* sp->sp_warn */   */
184   );   /* fields:     2 3  4 5     6 78 */
185   fclose(file);   p = xasprintf("!:%u:0:99999:7:::", (unsigned)(time(NULL)) / (24*60*60));
186   }   /* ignore errors: if file is missing we suppose admin doesn't want it */
187     update_passwd(bb_path_shadow_file, pw.pw_name, p, NULL);
188     if (ENABLE_FEATURE_CLEAN_UP)
189     free(p);
190  #endif  #endif
191    
192   /* add to group */   /* add to group */
193   /* addgroup should be responsible for dealing w/ gshadow */   addgroup_wrapper(&pw, usegroup);
  /* if using a pre-existing group, don't create one */  
  if (!usegroup)  
  addgroup_wrapper(&pw);  
194    
195   /* Clear the umask for this process so it doesn't   /* clear the umask for this process so it doesn't
196   * screw up the permissions on the mkdir and chown. */   * screw up the permissions on the mkdir and chown. */
197   umask(0);   umask(0);
198   if (!(option_mask32 & OPT_DONT_MAKE_HOME)) {   if (!(opts & OPT_DONT_MAKE_HOME)) {
199   /* Set the owner and group so it is owned by the new user,   /* set the owner and group so it is owned by the new user,
200     then fix up the permissions to 2755. Can't do it before   * then fix up the permissions to 2755. Can't do it before
201     since chown will clear the setgid bit */   * since chown will clear the setgid bit */
202   if (mkdir(pw.pw_dir, 0755)   if ((mkdir(pw.pw_dir, 0755) != 0 && errno != EEXIST)
203   || chown(pw.pw_dir, pw.pw_uid, pw.pw_gid)   || chown(pw.pw_dir, pw.pw_uid, pw.pw_gid) != 0
204   || chmod(pw.pw_dir, 02755) /* set setgid bit on homedir */   || chmod(pw.pw_dir, 02755) != 0 /* set setgid bit on homedir */
205   ) {   ) {
206   bb_simple_perror_msg(pw.pw_dir);   bb_simple_perror_msg(pw.pw_dir);
207   }   }
208   }   }
209    
210   if (!(option_mask32 & OPT_DONT_SET_PASS)) {   if (!(opts & OPT_DONT_SET_PASS)) {
211   /* interactively set passwd */   /* interactively set passwd */
212   passwd_wrapper(pw.pw_name);   passwd_wrapper(pw.pw_name);
213   }   }

Legend:
Removed from v.983  
changed lines
  Added in v.984