SlideShare uma empresa Scribd logo
1 de 33
Baixar para ler offline
env	
  EDITOR=vipw	
  vipw	
  
         してみた	
  
          @yogata	
  
vipw	
  

•  ユーザ追加・削除・情報変更する	
  
                         vipw	
                useradd/adduser	
  
   メリット	
                Jviが使える	
            特に無い	
  
   デメリット	
               特にない	
                Luserとaddのどっちが
                                               先かわからない	
  




•  vipw	
  is	
  神	
  
こんなにもすばらしいvipw	
  
•  使いたくなってきたはず	
  
	
  
•  でも……viは慣れてないし……	
  




         env	
  EDITOR=XXX	
  vipw	
  
vipw	
  と	
  EDITOR変数	
  
•  env	
  EDITOR=nano	
  vipw	
  
vipw	
  と	
  EDITOR変数	
  
•  env	
  EDITOR=emacs	
  vipw	
  
vipw	
  と	
  EDITOR変数	
  
(	
  ^o^)	
  env	
  EDITOR=emacs	
  vipw	
  →	
  emacsで開く	
  
	
  
(	
  ˘⊖˘)	
  。o(	
  env	
  EDITOR=vipw	
  vipwしたらどうなるんだ)	
  
	
  
|Terminal.app|	
  ┗(☋` )┓三 	
  
	
  
(	
  ◠‿◠	
  )☛	
  そこに気づいてしまったか	
  
	
  
▂▅▇█▓▒░(’ω’)░▒▓█▇▅▂うわあああああああ
やってみる	
  
#	
  env	
  EDITOR=vipw	
  vipw	
  


 rootになるのを
    忘れずに	
  
やってみる	
  
調べる	
  
•  FreeBSD	
  
   –  /usr/src/usr.sbin/vipw/vipw.c	
  
   –  /usr/src/lib/libuMl/pw_uMl.c	
  

   –  /usr/include/pwd.h	
  

   –  err周りはここらへん	
  
       •  /usr/src/lib/libc/gen/err.c	
  
vipw.c	
  (1/3)	
  
	
  	
  	
  65	
  int	
  
	
  	
  	
  66	
  main(int	
  argc,	
  char	
  *argv[])	
  
	
  	
  	
  67	
  {	
  
	
  	
  	
  68	
  	
  	
  	
  	
  const	
  char	
  *passwd_dir	
  =	
  NULL;	
  
	
  	
  	
  69	
  	
  	
  	
  	
  int	
  ch,	
  pfd,	
  ad;	
  
	
  	
  	
  70	
  	
  	
  	
  	
  char	
  *line;	
  
	
  	
  	
  71	
  	
  	
  	
  	
  size_t	
  len;	
  
	
  	
  	
  72	
  	
  
	
  	
  	
  73	
  	
  	
  	
  	
  while	
  ((ch	
  =	
  getopt(argc,	
  argv,	
  "d:"))	
  !=	
  -­‐1)	
  
	
  	
  	
  74	
  	
  	
  	
  	
  	
  	
  	
  	
  switch	
  (ch)	
  {	
  
	
  	
  	
  75	
  	
  	
  	
  	
  	
  	
  	
  	
  case	
  'd':	
                                             vipwのオプションは-­‐dだけ.それ
	
  	
  	
  76	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  passwd_dir	
  =	
  optarg;	
               以外のオプションが来たらusage()
	
  	
  	
  77	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  break;	
                                   する	
  
	
  	
  	
  78	
  	
  	
  	
  	
  	
  	
  	
  	
  case	
  '?':	
  
	
  	
  	
  79	
  	
  	
  	
  	
  	
  	
  	
  	
  default:	
  
	
  	
  	
  80	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  usage();	
  
	
  	
  	
  81	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  82	
  	
  
	
  	
  	
  83	
  	
  	
  	
  	
  argc	
  -­‐=	
  opMnd;	
  
	
  	
  	
  84	
  	
  	
  	
  	
  argv	
  +=	
  opMnd;	
  
vipw.c	
  (2/3)	
  
	
  	
  	
  85	
  	
  
	
  	
  	
  86	
  	
  	
  	
  	
  if	
  (argc	
  !=	
  0)	
  
	
  	
  	
  87	
  	
  	
  	
  	
  	
  	
  	
  	
  usage();	
  
	
  	
  	
  88	
  	
  
	
  	
  	
  89	
  	
  	
  	
  	
  if	
  (pw_init(passwd_dir,	
  NULL)	
  ==	
  -­‐1)	
                             pw_init()	
  ?	
  
	
  	
  	
  90	
  	
  	
  	
  	
  	
  	
  	
  	
  err(1,	
  "pw_init()");	
  
	
  	
  	
  91	
  	
  	
  	
  	
  if	
  ((pfd	
  =	
  pw_lock())	
  ==	
  -­‐1)	
  {	
  
	
  	
  	
  92	
  	
  	
  	
  	
  	
  	
  	
  	
  pw_fini();	
  
	
  	
  	
  93	
  	
  	
  	
  	
  	
  	
  	
  	
  err(1,	
  "pw_lock()");	
                                        pw_lock()	
  ?	
  
	
  	
  	
  94	
  	
  	
  	
  	
  }	
  
	
  	
  	
  95	
  	
  	
  	
  	
  if	
  ((ad	
  =	
  pw_tmp(pfd))	
  ==	
  -­‐1)	
  {	
  
	
  	
  	
  96	
  	
  	
  	
  	
  	
  	
  	
  	
  pw_fini();	
  
	
  	
  	
  97	
  	
  	
  	
  	
  	
  	
  	
  	
  err(1,	
  "pw_tmp()");	
                                         pw_tmp()	
  ?	
  
	
  	
  	
  98	
  	
  	
  	
  	
  }	
  
	
  	
  	
  99	
  	
  	
  	
  	
  (void)close(ad);	
  
	
  	
  100	
  	
  	
  	
  	
  /*	
  Force	
  umask	
  for	
  parMal	
  writes	
  made	
  in	
  the	
  edit	
  phase	
  */	
  
	
  	
  101	
  	
  	
  	
  	
  (void)umask(077);	
  
vipw.c	
  (3/3)	
  
	
  	
  103	
  	
  	
  	
  	
  for	
  (;;)	
  {	
                                                                   	
  	
  118	
  	
  	
  	
  	
  	
  	
  	
  	
  prina("re-­‐edit	
  the	
  password	
  file?	
  ");	
  
	
  	
  104	
  	
  	
  	
  	
  	
  	
  	
  	
  switch	
  (pw_edit(0))	
  {	
                                        	
  	
  119	
  	
  	
  	
  	
  	
  	
  	
  	
  fflush(stdout);	
  
	
  	
  105	
  	
  	
  	
  	
  	
  	
  	
  	
  case	
  -­‐1:	
                                                      	
  	
  120	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  ((line	
  =	
  fgetln(stdin,	
  &len))	
  ==	
  NULL)	
  {	
  
	
  	
  106	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  pw_fini();	
                                          	
  	
  121	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  pw_fini();	
  
	
  	
  107	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  err(1,	
  "pw_edit()");	
                            	
  	
  122	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  err(1,	
  "fgetln()");	
  
	
  	
  108	
  	
  	
  	
  	
  	
  	
  	
  	
  case	
  0:	
                                                         	
  	
  123	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  109	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  pw_fini();	
                                          	
  	
  124	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (len	
  >	
  0	
  &&	
  (*line	
  ==	
  'N'	
  ||	
  *line	
  ==	
  'n'))	
  
	
  	
  110	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  errx(0,	
  "no	
  changes	
  made");	
               	
  	
  125	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  break;	
  
	
  	
  111	
  	
  	
  	
  	
  	
  	
  	
  	
  default:	
                                                           	
  	
  126	
  	
  	
  	
  	
  }	
  
	
  	
  112	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  break;	
                                             	
  	
  127	
  	
  	
  	
  	
  pw_fini();	
  
	
  	
  113	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
                                                                  	
  	
  128	
  	
  	
  	
  	
  exit(0);	
  
	
  	
  114	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (pw_mkdb(NULL)	
  ==	
  0)	
  {	
                              	
  	
  129	
  }	
  
	
  	
  115	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  pw_fini();	
                                                                   パスワードファイルを再構築に失
	
  	
  116	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  errx(0,	
  "password	
  list	
  updated");	
                                  敗したら,再度ファイルを編集する
	
  	
  117	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
                                                                                                                                             か確認する	
  



                                                                                                     pw_edit()	
  ?	
  

  pw_mkdb()	
  ?	
  
vipw.c	
  まとめ	
  
          オプション処理.-­‐dだけ	
  




       キニナル	
  
pw_init()	
  (1/2)	
  
	
  93	
  int	
  
	
  94	
  pw_init(const	
  char	
  *dir,	
  const	
  char	
  *master)	
  
	
  95	
  {	
  
	
  96	
  #if	
  0	
  
	
  97	
  	
  	
  	
  	
  struct	
  rlimit	
  rlim;	
  
	
  98	
  #endif	
  
	
  99	
  	
  
100	
  	
  	
  	
  	
  if	
  (dir	
  ==	
  NULL)	
  {	
  
101	
  	
  	
  	
  	
  	
  	
  	
  	
  strcpy(passwd_dir,	
  _PATH_ETC);	
                        -­‐dオプションが無ければ
102	
  	
  	
  	
  	
  }	
  else	
  {	
                                                           master.passwdファイルがあるディ
103	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (strlen(dir)	
  >=	
  sizeof(passwd_dir))	
  {	
     レクトリの初期値として_PATH_ETC
104	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  errno	
  =	
  ENAMETOOLONG;	
              を使う(/usr/include/pwd.h)	
  
105	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  (-­‐1);	
  
106	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
107	
  	
  	
  	
  	
  	
  	
  	
  	
  strcpy(passwd_dir,	
  dir);	
  
108	
  	
  	
  	
  	
  }	
  
109	
  	
  
pw_init()	
  (2/2)	
  
110	
  	
  	
  	
  	
  if	
  (master	
  ==	
  NULL)	
  {	
  
111	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (dir	
  ==	
  NULL)	
  {	
  
112	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  strcpy(masterpasswd,	
  _PATH_MASTERPASSWD);	
  
113	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  else	
  if	
  (snprina(masterpasswd,	
  sizeof(masterpasswd),	
  "%s/%s",	
  
114	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  passwd_dir,	
  _MASTERPASSWD)	
  >	
  (int)sizeof(masterpasswd))	
  {	
  
115	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  errno	
  =	
  ENAMETOOLONG;	
  
116	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  (-­‐1);	
  
117	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
118	
  	
  	
  	
  	
  }	
  else	
  {	
  
119	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (strlen(master)	
  >=	
  sizeof(masterpasswd))	
  {	
  
120	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  errno	
  =	
  ENAMETOOLONG;	
  
121	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  (-­‐1);	
  
122	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
                                                                     master.passwdのファイル名を指定す
123	
  	
  	
  	
  	
  	
  	
  	
  	
  strcpy(masterpasswd,	
  master);	
                                      ることができるが,vipw.cからはNULL
124	
  	
  	
  	
  	
  }	
                                                                                     なので_PATH_MASTERPASSWD	
  
                                                                                 (/usr/include/pwd.h)を使う	
  
vipw.c	
  まとめ	
  
          オプション処理.-­‐dだけ	
  


          パスワードファイルの場所を探す	
  
pw_lock()	
  	
  
	
  	
  166	
  int	
  
	
  	
  167	
  pw_lock(void)	
  
	
  	
  168	
  {	
  
	
  	
  169	
  	
  
	
  	
  170	
  	
  	
  	
  	
  if	
  (*masterpasswd	
  ==	
  '0')	
  
	
  	
  171	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  (-­‐1);	
  
<snip>	
  
	
  	
  179	
  	
  	
  	
  	
  for	
  (;;)	
  {	
  
	
  	
  180	
  	
  	
  	
  	
  	
  	
  	
  	
  struct	
  stat	
  st;	
  
	
  	
  181	
  	
  
	
  	
  182	
  	
  	
  	
  	
  	
  	
  	
  	
  lockfd	
  =	
  open(masterpasswd,	
  O_RDONLY,	
  0);	
  
                                                                                                                                                     master.passwdファイルを開いて	
  
	
  	
  183	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (lockfd	
  <	
  0	
  ||	
  fcntl(lockfd,	
  F_SETFD,	
  1)	
  ==	
  -­‐1)	
  
	
  	
  184	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  err(1,	
  "%s",	
  masterpasswd);	
  
	
  	
  185	
  	
  	
  	
  	
  	
  	
  	
  	
  /*	
  XXX	
  vulnerable	
  to	
  race	
  condiMons	
  */	
  
	
  	
  186	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (flock(lockfd,	
  LOCK_EX|LOCK_NB)	
  ==	
  -­‐1)	
  {	
                                         ロックする	
  
	
  	
  187	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (errno	
  ==	
  EWOULDBLOCK)	
  {	
  
	
  	
  188	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  errx(1,	
  "the	
  password	
  db	
  file	
  is	
  busy");	
  
	
  	
  189	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  else	
  {	
  
	
  	
  190	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  err(1,	
  "could	
  not	
  lock	
  the	
  passwd	
  file:	
  ");	
  
	
  	
  191	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  192	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
<snip>	
  
vipw.c	
  まとめ	
  
          オプション処理.-­‐dだけ	
  


          パスワードファイルの場所を探す	
  


          パスワードファイルをロックする	
  
pw_tmp()	
  (1/2)	
  
	
  	
  213	
  int	
  
	
  	
  214	
  pw_tmp(int	
  mfd)	
  
	
  	
  215	
  {	
  
	
  	
  216	
  	
  	
  	
  	
  char	
  buf[8192];	
  
	
  	
  217	
  	
  	
  	
  	
  ssize_t	
  nr;	
  
	
  	
  218	
  	
  	
  	
  	
  const	
  char	
  *p;	
  
	
  	
  219	
  	
  	
  	
  	
  int	
  ad;	
  
	
  	
  220	
  	
  
	
  	
  221	
  	
  	
  	
  	
  if	
  (*masterpasswd	
  ==	
  '0')	
                                                   master.passwdファイルがあるディ
	
  	
  222	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  (-­‐1);	
                                                     レクトリに一時ファイルpw.XXXXXX	
  
	
  	
  223	
  	
  	
  	
  	
  if	
  ((p	
  =	
  strrchr(masterpasswd,	
  '/')))	
  
                                                                                                                       (Xは乱数に置き換え)を作成.	
  
	
  	
  224	
  	
  	
  	
  	
  	
  	
  	
  	
  ++p;	
  
	
  	
  225	
  	
  	
  	
  	
  else	
  
	
  	
  226	
  	
  	
  	
  	
  	
  	
  	
  	
  p	
  =	
  masterpasswd;	
  
	
  	
  227	
  	
  	
  	
  	
  if	
  (snprina(tempname,	
  sizeof(tempname),	
  "%.*spw.XXXXXX",	
  
	
  	
  228	
  	
  	
  	
  	
  	
  	
  	
  	
  (int)(p	
  -­‐	
  masterpasswd),	
  masterpasswd)	
  >=	
  (int)sizeof(tempname))	
  {	
  
	
  	
  229	
  	
  	
  	
  	
  	
  	
  	
  	
  errno	
  =	
  ENAMETOOLONG;	
  
	
  	
  230	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  (-­‐1);	
  
	
  	
  231	
  	
  	
  	
  	
  }	
  
	
  	
  232	
  	
  	
  	
  	
  if	
  ((ad	
  =	
  mkstemp(tempname))	
  ==	
  -­‐1)	
  
	
  	
  233	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  (-­‐1);	
  
pw_tmp()	
  (2/2)	
  
	
  	
  234	
  	
  	
  	
  	
  if	
  (mfd	
  !=	
  -­‐1)	
  {	
  
	
  	
  235	
  	
  	
  	
  	
  	
  	
  	
  	
  while	
  ((nr	
  =	
  read(mfd,	
  buf,	
  sizeof(buf)))	
  >	
  0)	
      master.passwdの中身を
	
  	
  236	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (write(ad,	
  buf,	
  (size_t)nr)	
  !=	
  nr)	
     一時ファイルにコピー	
  
	
  	
  237	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  break;	
  
	
  	
  238	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (nr	
  !=	
  0)	
  {	
  
	
  	
  239	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  unlink(tempname);	
  
	
  	
  240	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  *tempname	
  =	
  '0';	
  
	
  	
  241	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  close(ad);	
  
	
  	
  242	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  (-­‐1);	
  
	
  	
  243	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  244	
  	
  	
  	
  	
  }	
  
	
  	
  245	
  	
  	
  	
  	
  return	
  (ad);	
  
	
  	
  246	
  }	
  
vipw.c	
  まとめ	
  
          オプション処理.-­‐dだけ	
  


          パスワードファイルの場所を探す	
  


          パスワードファイルをロックする	
  

          パスワードファイルと同じディレク
          トリに作業用ファイルを作って,
          中身をコピーする	
  
pw_edit()	
  (1/4)	
  
	
  	
  288	
  int	
  
	
  	
  289	
  pw_edit(int	
  notsetuid)	
  
	
  	
  290	
  {	
  
<snip>	
  
	
  	
  297	
  	
  	
  	
  	
  if	
  ((editor	
  =	
  getenv("EDITOR"))	
  ==	
  NULL)	
     パスワードファイルを編集する
	
  	
  298	
  	
  	
  	
  	
  	
  	
  	
  	
  editor	
  =	
  _PATH_VI;	
                    エディタを設定.EDITOR変数の
	
  	
  299	
  	
  	
  	
  	
  if	
  (stat(tempname,	
  &st1)	
  ==	
  -­‐1)	
  
	
  	
  300	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  (-­‐1);	
  
                                                                                             設定が無ければviを設定	
  
<snip>	
  
	
  
pw_edit()	
  (2/4)	
  
                                                                                           	
  	
  104	
  	
  	
  	
  	
  	
  	
  	
  	
  switch	
  (pw_edit(0))	
  {	
  
	
  	
  309	
  	
  	
  	
  	
  switch	
  ((editpid	
  =	
  fork()))	
  {	
                 	
  	
  105	
  	
  	
  	
  	
  	
  	
  	
  	
  case	
  -­‐1:	
  	
  
	
  	
  310	
  	
  	
  	
  	
  case	
  -­‐1:	
                                                                                                                                            vipw.c	
  
                                                                                           	
  	
  106	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  pw_fini();	
  
                                                                                                                                                           	
  
	
  	
  311	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  (-­‐1);	
                         	
  	
  107	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  e	
  rr(1,	
  "pw_edit()");	
  
	
  	
  312	
  	
  	
  	
  	
  case	
  0:	
                                                <snip>	
  
	
  	
  313	
  	
  	
  	
  	
  	
  	
  	
  	
  sigacMon(SIGINT,	
  &sa_int,	
  NULL);	
   	
  	
  113	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  314	
  	
  	
  	
  	
  	
  	
  	
  	
  sigacMon(SIGQUIT,	
  &sa_quit,	
  NULL);	
  
	
  	
  315	
  	
  	
  	
  	
  	
  	
  	
  	
  sigprocmask(SIG_SETMASK,	
  &oldsigset,	
  NULL);	
  
	
  	
  316	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (notsetuid)	
  {	
  
                                                                                                                                                                 master.passwdをコピーした一時
	
  	
  317	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  (void)setgid(getgid());	
  
                                                                                                                                                                 ファイル(tempname)を引数にし
	
  	
  318	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  (void)setuid(getuid());	
  
                                                                                                                                                                 てエディタ(editor)を開く.	
  
	
  	
  319	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  320	
  	
  	
  	
  	
  	
  	
  	
  	
  errno	
  =	
  0;	
  
	
  	
  321	
  	
  	
  	
  	
  	
  	
  	
  	
  execlp(editor,	
  basename(editor),	
  tempname,	
  (char	
  *)NULL);	
  
	
  	
  322	
  	
  	
  	
  	
  	
  	
  	
  	
  _exit(errno);	
  
	
  	
  323	
  	
  	
  	
  	
  default:	
                                                                                       後述	
  
	
  	
  324	
  	
  	
  	
  	
  	
  	
  	
  	
  /*	
  parent	
  */	
  
	
  	
  325	
  	
  	
  	
  	
  	
  	
  	
  	
  break;	
  
	
  	
  326	
  	
  	
  	
  	
  }	
  
pw_edit()	
  (3/4)	
  
	
  	
  327	
  	
  	
  	
  	
  for	
  (;;)	
  {	
                                                                           エラーだったらファイルを削除し
	
  	
  328	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (waitpid(editpid,	
  &pstat,	
  WUNTRACED)	
  ==	
  -­‐1)	
  {	
       て終了する	
  
	
  	
  329	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (errno	
  ==	
  EINTR)	
  
	
  	
  330	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  conMnue;	
  
	
  	
  331	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  unlink(tempname);	
  
	
  	
  332	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  editpid	
  =	
  -­‐1;	
  
	
  	
  333	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  break;	
                                                              execlp()が正常終了したら一時
	
  	
  334	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  else	
  if	
  (WIFSTOPPED(pstat))	
  {	
                                         ファイルを残して終了する	
  
	
  	
  335	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  raise(WSTOPSIG(pstat));	
  
	
  	
  336	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  else	
  if	
  (WIFEXITED(pstat)	
  &&	
  WEXITSTATUS(pstat)	
  ==	
  0)	
  {	
  
	
  	
  337	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  editpid	
  =	
  -­‐1;	
  
	
  	
  338	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  break;	
  
	
  	
  339	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  else	
  {	
  
	
  	
  340	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  unlink(tempname);	
  
	
  	
  341	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  editpid	
  =	
  -­‐1;	
  
	
  	
  342	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  break;	
                          execlp()が異常終了したら一時
	
  	
  343	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
                                                                                                 ファイルを削除して終了する	
  
	
  	
  344	
  	
  	
  	
  	
  }	
  



                       waitpid()でエラーだったり,execlp()が異常終了したらファイルを削除する	
  
pw_edit()	
  (4/4)	
  
	
  	
  345	
  	
  	
  	
  	
  sigacMon(SIGINT,	
  &sa_int,	
  NULL);	
  
	
  	
  346	
  	
  	
  	
  	
  sigacMon(SIGQUIT,	
  &sa_quit,	
  NULL);	
                        waitpid()でエラーだったりexeclp()で不
	
  	
  347	
  	
  	
  	
  	
  sigprocmask(SIG_SETMASK,	
  &oldsigset,	
  NULL);	
  
                                                                                                 正終了していたらtempnameファイルは
	
  	
  348	
  	
  	
  	
  	
  if	
  (stat(tempname,	
  &st2)	
  ==	
  -­‐1)	
  {	
  
	
  	
  349	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  (-­‐1);	
                               無いのでstat()が-­‐1になりreturn(-­‐1)	
  
	
  	
  350	
  	
  	
  	
  	
  }	
  
	
  	
  351	
  	
  	
  	
  	
  return	
  (st1.st_mMme	
  !=	
  st2.st_mMme);	
                                     execlp()が正常終了したら一時
	
  	
  352	
  }	
                                                                                                 ファイルを残して終了する	
  


                                                                   	
  	
  104	
  	
  	
  	
  	
  	
  	
  	
  	
  switch	
  (pw_edit(0))	
  {	
                    vipw.c	
  
  EDITORの終了を失敗し                                                    	
  	
  105	
  	
  	
  	
  	
  	
  	
  	
  	
  case	
  -­‐1:	
  
  たり,execlp()でEDITOR                                               	
  	
  106	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  pw_fini();	
  
  が不正終了した場合	
                                                      	
  	
  107	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  err(1,	
  "pw_edit()");	
  
                                                                   	
  	
  108	
  	
  	
  	
  	
  	
  	
  	
  	
  case	
  0:	
  
  変更がない時	
                                                         	
  	
  109	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  pw_fini();	
  
                                                                   	
  	
  110	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  errx(0,	
  "no	
  changes	
  made");	
  
                                                                   	
  	
  111	
  	
  	
  	
  	
  	
  	
  	
  	
  default:	
  
  変更がある時	
                                                         	
  	
  112	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  break;	
  
                                                                   	
  	
  113	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
後述のアレ	
  
pw_edit()のところで	
  
	
  
     	
  execlp(editor,	
  basename(editor),	
  tempname,	
  (char	
  *)NULL);	
  
     	
   	
   	
   	
   	
   	
  ↓	
  
     	
  execlp(“vipw”	
  “vipw”,	
  “pw.XXXXX”,	
  (char	
  *)NULL);	
  
	
  
こうなって,結局のところ	
  
	
  
     	
  #	
  vipw	
  pw.XXXXX	
  
	
  
な感じになる	
  
そういえば	
  
•  vipwコマンドに”pw.XXXXX”引数は不正なので
   usage()	
  
          	
  while	
  ((ch	
  =	
  getopt(argc,	
  argv,	
  "d:"))	
  !=	
  -­‐1)	
  
          	
   	
  switch	
  (ch)	
  {	
  
  …	
  
          	
     	
  default:	
  
          	
     	
   	
  usage();	
  
          	
     	
  }	
  

 #	
  env	
  EDITOR=vipw	
  vipw	
             つまりこうなる	
  
 usage:	
  vipw	
  [-­‐d	
  directory]	
  
 vipw:	
  pw_edit():	
  No	
  such	
  file	
  or	
  directory	
  
EDITORが不正終了したので	
  
	
  	
  327	
  	
  	
  	
  	
  for	
  (;;)	
  {	
  
	
  	
  328	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (waitpid(editpid,	
  &pstat,	
  WUNTRACED)	
  ==	
  -­‐1)	
  {	
  
	
  	
  329	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (errno	
  ==	
  EINTR)	
                                        pw_edit()	
  
	
  	
  330	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  conMnue;	
  
	
  	
  331	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  unlink(tempname);	
  
	
  	
  332	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  editpid	
  =	
  -­‐1;	
  
	
  	
  333	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  break;	
  
	
  	
  334	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  else	
  if	
  (WIFSTOPPED(pstat))	
  {	
  
	
  	
  335	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  raise(WSTOPSIG(pstat));	
  
	
  	
  336	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  else	
  if	
  (WIFEXITED(pstat)	
  &&	
  WEXITSTATUS(pstat)	
  ==	
  0)	
  {	
  
	
  	
  337	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  editpid	
  =	
  -­‐1;	
  
	
  	
  338	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  break;	
  
	
  	
  339	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  else	
  {	
  
	
  	
  340	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  unlink(tempname);	
  
	
  	
  341	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  editpid	
  =	
  -­‐1;	
  
	
  	
  342	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  break;	
                          execlp()が不正終了したら一時
	
  	
  343	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
                                                                                                 ファイルを削除して終了する	
  
	
  	
  344	
  	
  	
  	
  	
  }	
  
pw_edit()を振り返って	
  
	
  	
  345	
  	
  	
  	
  	
  sigacMon(SIGINT,	
  &sa_int,	
  NULL);	
  
	
  	
  346	
  	
  	
  	
  	
  sigacMon(SIGQUIT,	
  &sa_quit,	
  NULL);	
                           execlp()で不正終了していたら
	
  	
  347	
  	
  	
  	
  	
  sigprocmask(SIG_SETMASK,	
  &oldsigset,	
  NULL);	
  
                                                                                                    tempnameファイルは無いので	
  
	
  	
  348	
  	
  	
  	
  	
  if	
  (stat(tempname,	
  &st2)	
  ==	
  -­‐1)	
  {	
  
	
  	
  349	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  (-­‐1);	
                                  stat()が-­‐1になりreturn(-­‐1)	
  
	
  	
  350	
  	
  	
  	
  	
  }	
  
	
  	
  351	
  	
  	
  	
  	
  return	
  (st1.st_mMme	
  !=	
  st2.st_mMme);	
  
	
  	
  352	
  }	
  


                                                         	
  	
  104	
  	
  	
  	
  	
  	
  	
  	
  	
  switch	
  (pw_edit(0))	
  {	
                    vipw.c	
  
   EDITORの終了を失敗し                                         	
  	
  105	
  	
  	
  	
  	
  	
  	
  	
  	
  case	
  -­‐1:	
  
   たり,execlp()でEDITOR                                    	
  	
  106	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  pw_fini();	
  
   が不正終了した場合	
                                           	
  	
  107	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  err(1,	
  "pw_edit()");	
  
                                                         	
  	
  108	
  	
  	
  	
  	
  	
  	
  	
  	
  case	
  0:	
  
                                                         	
  	
  109	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  pw_fini();	
  
                                                         	
  	
  110	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  errx(0,	
  "no	
  changes	
  made");	
  
                                                         	
  	
  111	
  	
  	
  	
  	
  	
  	
  	
  	
  default:	
  
#	
  env	
  EDITOR=vipw	
  vipw	
                        	
  	
  112	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  break;	
  
usage:	
  vipw	
  [-­‐d	
  directory]	
                  	
  	
  113	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
vipw:	
  pw_edit():	
  No	
  such	
  file	
  or	
  directory	
  
vipw.c	
  まとめ	
  
           オプション処理.-­‐dだけ	
  


           パスワードファイルの場所を探す	
  


           パスワードファイルをロックする	
  

           パスワードファイルと同じディレク
           トリに作業用ファイルを作って,
           中身をコピーする	
  

   EDITORで指定したコマンドに作業用ファイルを渡したり,	
  
   コマンドが異常終了したら作業ファイルを消したり,	
  
   作業ファイルの更新時間を確認したり,	
  
   作業ファイルが消されてたら更新時間を確認できない
   のでエラーを返したり,	
  
   する.	
  
(参考)	
  env	
  EDITOR=nano	
  vipwのとき	
  
                             pw.XXXXX	
  の部分	
  
pw_mkdb()	
  
•  省略	
  
まとめ	
  
•  vipwは内部でexeclp()を使ってEDITORを実行し,引
   数に作業用ファイルを渡す	
  
•  1つ目のエラーはEDITOR=vipwの時にvipwコマンド
   が-­‐d以外の引数を許容しないエラー	
  
•  2つ目のエラーは,1つ目のエラーに起因して作業用
   ファイルを消し,その後の処理で作業用ファイルを
   見に行こうとするが存在しないので出るエラー	
  

 #	
  env	
  EDITOR=vipw	
  vipw	
  
 usage:	
  vipw	
  [-­‐d	
  directory]	
  
 vipw:	
  pw_edit():	
  No	
  such	
  file	
  or	
  directory	
  

Mais conteúdo relacionado

Destaque

Glasriket - inspiration kring design
Glasriket - inspiration kring designGlasriket - inspiration kring design
Glasriket - inspiration kring designSVID
 
EICG BD Company Profile
EICG BD Company ProfileEICG BD Company Profile
EICG BD Company Profileaelnady
 
2012 1-00105-if bab 5
2012 1-00105-if bab 52012 1-00105-if bab 5
2012 1-00105-if bab 5Jabarin Koni
 
超簡単!TELNETの話
超簡単!TELNETの話超簡単!TELNETの話
超簡単!TELNETの話ogatay
 
Social Media Plan for TATA DoCoMo WAT CONSULT
Social Media Plan for TATA DoCoMo WAT CONSULTSocial Media Plan for TATA DoCoMo WAT CONSULT
Social Media Plan for TATA DoCoMo WAT CONSULTMohin Khan
 

Destaque (6)

Glasriket - inspiration kring design
Glasriket - inspiration kring designGlasriket - inspiration kring design
Glasriket - inspiration kring design
 
EICG BD Company Profile
EICG BD Company ProfileEICG BD Company Profile
EICG BD Company Profile
 
2012 1-00105-if bab 5
2012 1-00105-if bab 52012 1-00105-if bab 5
2012 1-00105-if bab 5
 
超簡単!TELNETの話
超簡単!TELNETの話超簡単!TELNETの話
超簡単!TELNETの話
 
Iageovanyangulo
IageovanyanguloIageovanyangulo
Iageovanyangulo
 
Social Media Plan for TATA DoCoMo WAT CONSULT
Social Media Plan for TATA DoCoMo WAT CONSULTSocial Media Plan for TATA DoCoMo WAT CONSULT
Social Media Plan for TATA DoCoMo WAT CONSULT
 

env EDITOR=vipw vipwしてみた

  • 1. env  EDITOR=vipw  vipw   してみた   @yogata  
  • 2. vipw   •  ユーザ追加・削除・情報変更する   vipw   useradd/adduser   メリット   Jviが使える   特に無い   デメリット   特にない   Luserとaddのどっちが 先かわからない   •  vipw  is  神  
  • 3. こんなにもすばらしいvipw   •  使いたくなってきたはず     •  でも……viは慣れてないし……   env  EDITOR=XXX  vipw  
  • 4. vipw  と  EDITOR変数   •  env  EDITOR=nano  vipw  
  • 5. vipw  と  EDITOR変数   •  env  EDITOR=emacs  vipw  
  • 6. vipw  と  EDITOR変数   (  ^o^)  env  EDITOR=emacs  vipw  →  emacsで開く     (  ˘⊖˘)  。o(  env  EDITOR=vipw  vipwしたらどうなるんだ)     |Terminal.app|  ┗(☋` )┓三     (  ◠‿◠  )☛  そこに気づいてしまったか     ▂▅▇█▓▒░(’ω’)░▒▓█▇▅▂うわあああああああ
  • 7. やってみる   #  env  EDITOR=vipw  vipw   rootになるのを 忘れずに  
  • 9. 調べる   •  FreeBSD   –  /usr/src/usr.sbin/vipw/vipw.c   –  /usr/src/lib/libuMl/pw_uMl.c   –  /usr/include/pwd.h   –  err周りはここらへん   •  /usr/src/lib/libc/gen/err.c  
  • 10. vipw.c  (1/3)        65  int        66  main(int  argc,  char  *argv[])        67  {        68          const  char  *passwd_dir  =  NULL;        69          int  ch,  pfd,  ad;        70          char  *line;        71          size_t  len;        72          73          while  ((ch  =  getopt(argc,  argv,  "d:"))  !=  -­‐1)        74                  switch  (ch)  {        75                  case  'd':   vipwのオプションは-­‐dだけ.それ      76                          passwd_dir  =  optarg;   以外のオプションが来たらusage()      77                          break;   する        78                  case  '?':        79                  default:        80                          usage();        81                  }        82          83          argc  -­‐=  opMnd;        84          argv  +=  opMnd;  
  • 11. vipw.c  (2/3)        85          86          if  (argc  !=  0)        87                  usage();        88          89          if  (pw_init(passwd_dir,  NULL)  ==  -­‐1)   pw_init()  ?        90                  err(1,  "pw_init()");        91          if  ((pfd  =  pw_lock())  ==  -­‐1)  {        92                  pw_fini();        93                  err(1,  "pw_lock()");   pw_lock()  ?        94          }        95          if  ((ad  =  pw_tmp(pfd))  ==  -­‐1)  {        96                  pw_fini();        97                  err(1,  "pw_tmp()");   pw_tmp()  ?        98          }        99          (void)close(ad);      100          /*  Force  umask  for  parMal  writes  made  in  the  edit  phase  */      101          (void)umask(077);  
  • 12. vipw.c  (3/3)      103          for  (;;)  {      118                  prina("re-­‐edit  the  password  file?  ");      104                  switch  (pw_edit(0))  {      119                  fflush(stdout);      105                  case  -­‐1:      120                  if  ((line  =  fgetln(stdin,  &len))  ==  NULL)  {      106                          pw_fini();      121                          pw_fini();      107                          err(1,  "pw_edit()");      122                          err(1,  "fgetln()");      108                  case  0:      123                  }      109                          pw_fini();      124                  if  (len  >  0  &&  (*line  ==  'N'  ||  *line  ==  'n'))      110                          errx(0,  "no  changes  made");      125                          break;      111                  default:      126          }      112                          break;      127          pw_fini();      113                  }      128          exit(0);      114                  if  (pw_mkdb(NULL)  ==  0)  {      129  }      115                          pw_fini();   パスワードファイルを再構築に失    116                          errx(0,  "password  list  updated");   敗したら,再度ファイルを編集する    117                  }   か確認する   pw_edit()  ?   pw_mkdb()  ?  
  • 13. vipw.c  まとめ   オプション処理.-­‐dだけ   キニナル  
  • 14. pw_init()  (1/2)    93  int    94  pw_init(const  char  *dir,  const  char  *master)    95  {    96  #if  0    97          struct  rlimit  rlim;    98  #endif    99     100          if  (dir  ==  NULL)  {   101                  strcpy(passwd_dir,  _PATH_ETC);   -­‐dオプションが無ければ 102          }  else  {   master.passwdファイルがあるディ 103                  if  (strlen(dir)  >=  sizeof(passwd_dir))  {   レクトリの初期値として_PATH_ETC 104                          errno  =  ENAMETOOLONG;   を使う(/usr/include/pwd.h)   105                          return  (-­‐1);   106                  }   107                  strcpy(passwd_dir,  dir);   108          }   109    
  • 15. pw_init()  (2/2)   110          if  (master  ==  NULL)  {   111                  if  (dir  ==  NULL)  {   112                          strcpy(masterpasswd,  _PATH_MASTERPASSWD);   113                  }  else  if  (snprina(masterpasswd,  sizeof(masterpasswd),  "%s/%s",   114                          passwd_dir,  _MASTERPASSWD)  >  (int)sizeof(masterpasswd))  {   115                          errno  =  ENAMETOOLONG;   116                          return  (-­‐1);   117                  }   118          }  else  {   119                  if  (strlen(master)  >=  sizeof(masterpasswd))  {   120                          errno  =  ENAMETOOLONG;   121                          return  (-­‐1);   122                  }   master.passwdのファイル名を指定す 123                  strcpy(masterpasswd,  master);   ることができるが,vipw.cからはNULL 124          }   なので_PATH_MASTERPASSWD   (/usr/include/pwd.h)を使う  
  • 16. vipw.c  まとめ   オプション処理.-­‐dだけ   パスワードファイルの場所を探す  
  • 17. pw_lock()        166  int      167  pw_lock(void)      168  {      169        170          if  (*masterpasswd  ==  '0')      171                  return  (-­‐1);   <snip>      179          for  (;;)  {      180                  struct  stat  st;      181        182                  lockfd  =  open(masterpasswd,  O_RDONLY,  0);   master.passwdファイルを開いて      183                  if  (lockfd  <  0  ||  fcntl(lockfd,  F_SETFD,  1)  ==  -­‐1)      184                          err(1,  "%s",  masterpasswd);      185                  /*  XXX  vulnerable  to  race  condiMons  */      186                  if  (flock(lockfd,  LOCK_EX|LOCK_NB)  ==  -­‐1)  {   ロックする      187                          if  (errno  ==  EWOULDBLOCK)  {      188                                  errx(1,  "the  password  db  file  is  busy");      189                          }  else  {      190                                  err(1,  "could  not  lock  the  passwd  file:  ");      191                          }      192                  }   <snip>  
  • 18. vipw.c  まとめ   オプション処理.-­‐dだけ   パスワードファイルの場所を探す   パスワードファイルをロックする  
  • 19. pw_tmp()  (1/2)      213  int      214  pw_tmp(int  mfd)      215  {      216          char  buf[8192];      217          ssize_t  nr;      218          const  char  *p;      219          int  ad;      220        221          if  (*masterpasswd  ==  '0')   master.passwdファイルがあるディ    222                  return  (-­‐1);   レクトリに一時ファイルpw.XXXXXX      223          if  ((p  =  strrchr(masterpasswd,  '/')))   (Xは乱数に置き換え)を作成.      224                  ++p;      225          else      226                  p  =  masterpasswd;      227          if  (snprina(tempname,  sizeof(tempname),  "%.*spw.XXXXXX",      228                  (int)(p  -­‐  masterpasswd),  masterpasswd)  >=  (int)sizeof(tempname))  {      229                  errno  =  ENAMETOOLONG;      230                  return  (-­‐1);      231          }      232          if  ((ad  =  mkstemp(tempname))  ==  -­‐1)      233                  return  (-­‐1);  
  • 20. pw_tmp()  (2/2)      234          if  (mfd  !=  -­‐1)  {      235                  while  ((nr  =  read(mfd,  buf,  sizeof(buf)))  >  0)   master.passwdの中身を    236                          if  (write(ad,  buf,  (size_t)nr)  !=  nr)   一時ファイルにコピー      237                                  break;      238                  if  (nr  !=  0)  {      239                          unlink(tempname);      240                          *tempname  =  '0';      241                          close(ad);      242                          return  (-­‐1);      243                  }      244          }      245          return  (ad);      246  }  
  • 21. vipw.c  まとめ   オプション処理.-­‐dだけ   パスワードファイルの場所を探す   パスワードファイルをロックする   パスワードファイルと同じディレク トリに作業用ファイルを作って, 中身をコピーする  
  • 22. pw_edit()  (1/4)      288  int      289  pw_edit(int  notsetuid)      290  {   <snip>      297          if  ((editor  =  getenv("EDITOR"))  ==  NULL)   パスワードファイルを編集する    298                  editor  =  _PATH_VI;   エディタを設定.EDITOR変数の    299          if  (stat(tempname,  &st1)  ==  -­‐1)      300                  return  (-­‐1);   設定が無ければviを設定   <snip>    
  • 23. pw_edit()  (2/4)      104                  switch  (pw_edit(0))  {      309          switch  ((editpid  =  fork()))  {      105                  case  -­‐1:        310          case  -­‐1:   vipw.c      106                          pw_fini();        311                  return  (-­‐1);      107                          e  rr(1,  "pw_edit()");      312          case  0:   <snip>      313                  sigacMon(SIGINT,  &sa_int,  NULL);      113                  }      314                  sigacMon(SIGQUIT,  &sa_quit,  NULL);      315                  sigprocmask(SIG_SETMASK,  &oldsigset,  NULL);      316                  if  (notsetuid)  {   master.passwdをコピーした一時    317                          (void)setgid(getgid());   ファイル(tempname)を引数にし    318                          (void)setuid(getuid());   てエディタ(editor)を開く.      319                  }      320                  errno  =  0;      321                  execlp(editor,  basename(editor),  tempname,  (char  *)NULL);      322                  _exit(errno);      323          default:   後述      324                  /*  parent  */      325                  break;      326          }  
  • 24. pw_edit()  (3/4)      327          for  (;;)  {   エラーだったらファイルを削除し    328                  if  (waitpid(editpid,  &pstat,  WUNTRACED)  ==  -­‐1)  {   て終了する      329                          if  (errno  ==  EINTR)      330                                  conMnue;      331                          unlink(tempname);      332                          editpid  =  -­‐1;      333                          break;   execlp()が正常終了したら一時    334                  }  else  if  (WIFSTOPPED(pstat))  {   ファイルを残して終了する      335                          raise(WSTOPSIG(pstat));      336                  }  else  if  (WIFEXITED(pstat)  &&  WEXITSTATUS(pstat)  ==  0)  {      337                          editpid  =  -­‐1;      338                          break;      339                  }  else  {      340                          unlink(tempname);      341                          editpid  =  -­‐1;      342                          break;   execlp()が異常終了したら一時    343                  }   ファイルを削除して終了する      344          }   waitpid()でエラーだったり,execlp()が異常終了したらファイルを削除する  
  • 25. pw_edit()  (4/4)      345          sigacMon(SIGINT,  &sa_int,  NULL);      346          sigacMon(SIGQUIT,  &sa_quit,  NULL);   waitpid()でエラーだったりexeclp()で不    347          sigprocmask(SIG_SETMASK,  &oldsigset,  NULL);   正終了していたらtempnameファイルは    348          if  (stat(tempname,  &st2)  ==  -­‐1)  {      349                  return  (-­‐1);   無いのでstat()が-­‐1になりreturn(-­‐1)      350          }      351          return  (st1.st_mMme  !=  st2.st_mMme);   execlp()が正常終了したら一時    352  }   ファイルを残して終了する      104                  switch  (pw_edit(0))  {   vipw.c   EDITORの終了を失敗し    105                  case  -­‐1:   たり,execlp()でEDITOR    106                          pw_fini();   が不正終了した場合      107                          err(1,  "pw_edit()");      108                  case  0:   変更がない時      109                          pw_fini();      110                          errx(0,  "no  changes  made");      111                  default:   変更がある時      112                          break;      113                  }  
  • 26. 後述のアレ   pw_edit()のところで      execlp(editor,  basename(editor),  tempname,  (char  *)NULL);              ↓    execlp(“vipw”  “vipw”,  “pw.XXXXX”,  (char  *)NULL);     こうなって,結局のところ      #  vipw  pw.XXXXX     な感じになる  
  • 27. そういえば   •  vipwコマンドに”pw.XXXXX”引数は不正なので usage()    while  ((ch  =  getopt(argc,  argv,  "d:"))  !=  -­‐1)      switch  (ch)  {   …      default:        usage();      }   #  env  EDITOR=vipw  vipw   つまりこうなる   usage:  vipw  [-­‐d  directory]   vipw:  pw_edit():  No  such  file  or  directory  
  • 28. EDITORが不正終了したので      327          for  (;;)  {      328                  if  (waitpid(editpid,  &pstat,  WUNTRACED)  ==  -­‐1)  {      329                          if  (errno  ==  EINTR)   pw_edit()      330                                  conMnue;      331                          unlink(tempname);      332                          editpid  =  -­‐1;      333                          break;      334                  }  else  if  (WIFSTOPPED(pstat))  {      335                          raise(WSTOPSIG(pstat));      336                  }  else  if  (WIFEXITED(pstat)  &&  WEXITSTATUS(pstat)  ==  0)  {      337                          editpid  =  -­‐1;      338                          break;      339                  }  else  {      340                          unlink(tempname);      341                          editpid  =  -­‐1;      342                          break;   execlp()が不正終了したら一時    343                  }   ファイルを削除して終了する      344          }  
  • 29. pw_edit()を振り返って      345          sigacMon(SIGINT,  &sa_int,  NULL);      346          sigacMon(SIGQUIT,  &sa_quit,  NULL);   execlp()で不正終了していたら    347          sigprocmask(SIG_SETMASK,  &oldsigset,  NULL);   tempnameファイルは無いので      348          if  (stat(tempname,  &st2)  ==  -­‐1)  {      349                  return  (-­‐1);   stat()が-­‐1になりreturn(-­‐1)      350          }      351          return  (st1.st_mMme  !=  st2.st_mMme);      352  }      104                  switch  (pw_edit(0))  {   vipw.c   EDITORの終了を失敗し    105                  case  -­‐1:   たり,execlp()でEDITOR    106                          pw_fini();   が不正終了した場合      107                          err(1,  "pw_edit()");      108                  case  0:      109                          pw_fini();      110                          errx(0,  "no  changes  made");      111                  default:   #  env  EDITOR=vipw  vipw      112                          break;   usage:  vipw  [-­‐d  directory]      113                  }   vipw:  pw_edit():  No  such  file  or  directory  
  • 30. vipw.c  まとめ   オプション処理.-­‐dだけ   パスワードファイルの場所を探す   パスワードファイルをロックする   パスワードファイルと同じディレク トリに作業用ファイルを作って, 中身をコピーする   EDITORで指定したコマンドに作業用ファイルを渡したり,   コマンドが異常終了したら作業ファイルを消したり,   作業ファイルの更新時間を確認したり,   作業ファイルが消されてたら更新時間を確認できない のでエラーを返したり,   する.  
  • 31. (参考)  env  EDITOR=nano  vipwのとき   pw.XXXXX  の部分  
  • 33. まとめ   •  vipwは内部でexeclp()を使ってEDITORを実行し,引 数に作業用ファイルを渡す   •  1つ目のエラーはEDITOR=vipwの時にvipwコマンド が-­‐d以外の引数を許容しないエラー   •  2つ目のエラーは,1つ目のエラーに起因して作業用 ファイルを消し,その後の処理で作業用ファイルを 見に行こうとするが存在しないので出るエラー   #  env  EDITOR=vipw  vipw   usage:  vipw  [-­‐d  directory]   vipw:  pw_edit():  No  such  file  or  directory