Linux的命令大部分都是busybox中实现的,addUser也是,用来添加一个用户
主要参数
-c:加上备注文字,备注文字保存在passwd的备注栏中。
-d:指定用户登入时的启始目录。
-D:变更预设值。
-e:指定账号的有效期限,缺省表示永久有效。
-f:指定在密码过期后多少天即关闭该账号。
-g:指定用户所属的群组。
-G:指定用户所属的附加群组。
-m:自动建立用户的登入目录。
-M:不要自动建立用户的登入目录。
-n:取消建立以用户名称为名的群组。
-r:建立系统账号。
-s:指定用户登入后所使用的shell。
-u:指定用户ID号。
下面来看看addUser的实现
addUser的实现比较简单,主要是解析用户的命令行参数,然后将相关信息保存到/etc/passwd。
我们先来看adduser_main
/* * adduser will take a login_name as its first parameter. * * home * shell * gecos * * can be customized via command-line parameters. * ________________________________________________________________________ */ int adduser_main(int argc, char **argv) { struct passwd pw; const char *usegroup = NULL; unsigned long flags; pw.pw_gecos = "Linux User,,,"; pw.pw_shell = (char *)DEFAULT_SHELL; pw.pw_dir = NULL; /* check for min, max and missing args and exit on error */ bb_opt_complementally = "-1:?1:?";//获取参数 flags = bb_getopt_ulflags(argc, argv, "h:g:s:G:DSH", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup); /* got root? */ if(geteuid()) { bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); } /* create string for $HOME if not specified already */ if (!pw.pw_dir) { snprintf(bb_common_bufsiz1, BUFSIZ, "/home/%s", argv[optind]); pw.pw_dir = &bb_common_bufsiz1[0]; } /* create a passwd struct */ pw.pw_name = argv[optind]; pw.pw_passwd = "x"; pw.pw_uid = 0; pw.pw_gid = (usegroup) ? bb_xgetgrnam(usegroup) : 0; /* exits on failure */ /* grand finale */ return adduser(&pw, flags);//调用另外一个add函数 }
这段代码是新建一个passwd结构保存一些用户相关信息,解析adduser命令的选项保存到flags,并最终调用adduser
/* putpwent(3) remix */ static int adduser(struct passwd *p, unsigned long flags) { FILE *file; int addgroup = !p->pw_gid; /* make sure everything is kosher and setup uid && gid */ file = bb_xfopen(bb_path_passwd_file, "a"); fseek(file, 0, SEEK_END); switch (passwd_study(bb_path_passwd_file, p)) {//赋值uid等 case 1: bb_error_msg_and_die("%s: login already in use", p->pw_name); case 2: bb_error_msg_and_die("illegal uid or no uids left"); case 3: bb_error_msg_and_die("%s: group name already in use", p->pw_name); } /* add to passwd */ if (putpwent(p, file) == -1) {//写回/etc/passwd bb_perror_nomsg_and_die(); } fclose(file); #if ENABLE_FEATURE_SHADOWPASSWDS /* add to shadow if necessary */ file = bb_xfopen(bb_path_shadow_file, "a"); fseek(file, 0, SEEK_END); fprintf(file, "%s:!:%ld:%d:%d:%d:::\n", p->pw_name, /* username */ time(NULL) / 86400, /* sp->sp_lstchg */ 0, /* sp->sp_min */ 99999, /* sp->sp_max */ 7); /* sp->sp_warn */ fclose(file); #endif /* add to group */ /* addgroup should be responsible for dealing w/ gshadow */ /* if using a pre-existing group, don't create one */ if (addgroup) addgroup_wrapper(p); /* Clear the umask for this process so it doesn't * * screw up the permissions on the mkdir and chown. */ umask(0); if (!(flags & DONT_MAKE_HOME)) { /* Set the owner and group so it is owned by the new user, then fix up the permissions to 2755. Can't do it before since chown will clear the setgid bit */ if (mkdir(p->pw_dir, 0755)//创建用户目录并修改拥有者和权限 || chown(p->pw_dir, p->pw_uid, p->pw_gid) || chmod(p->pw_dir, 02755)) { bb_perror_msg("%s", p->pw_dir); } } if (!(flags & DONT_SET_PASS)) { /* interactively set passwd */ passwd_wrapper(p->pw_name); } return 0; }
Adduser主要干了三件事:
1、 读取/etc/passwd/根据已经存在的用户来给新添加的用户赋值uid
2、 将赋值结果写回/etc/passwd
3、 创建用户目录,并修改权限等
我们看一下uid赋值的过程passwd_study
/* remix */ /* EDR recoded such that the uid may be passed in *p */ static int passwd_study(const char *filename, struct passwd *p) { struct passwd *pw; FILE *passwd; const int min = 500; const int max = 65000; passwd = bb_xfopen(filename, "r"); /* EDR if uid is out of bounds, set to min */ if ((p->pw_uid > max) || (p->pw_uid < min)) p->pw_uid = min; /* stuff to do: * make sure login isn't taken; * find free uid and gid; */ while ((pw = fgetpwent(passwd))) { if (strcmp(pw->pw_name, p->pw_name) == 0) {//已经存在同名用户 /* return 0; */ return 1; } if ((pw->pw_uid >= p->pw_uid) && (pw->pw_uid < max) && (pw->pw_uid >= min)) {//将其赋值为已存在uid + 1 p->pw_uid = pw->pw_uid + 1; } } if (p->pw_gid == 0) { /* EDR check for an already existing gid */ while (getgrgid(p->pw_uid) != NULL) p->pw_uid++; /* EDR also check for an existing group definition */ if (getgrnam(p->pw_name) != NULL) return 3; /* EDR create new gid always = uid */ p->pw_gid = p->pw_uid; } /* EDR bounds check */ if ((p->pw_uid > max) || (p->pw_uid < min)) return 2; /* return 1; */ return 0; }
这个函数也很简单,查找已经存在的uid的最大值,将待添加的用户的uid设置为最大值加1,当然,不能超过uid的最大值
从上面可以看到,adduser其实可以不用和内核打交道,只是将相关信息保存到了/etc/passwd,那我们使用ls –l显示的用户又是怎么来的呢,请看后面对ls的分析