Ruby 1.9.3p327(2012-11-10revision37606)
|
00001 /************************************************ 00002 00003 etc.c - 00004 00005 $Author: akr $ 00006 created at: Tue Mar 22 18:39:19 JST 1994 00007 00008 ************************************************/ 00009 00010 #include "ruby.h" 00011 #include "ruby/encoding.h" 00012 00013 #include <sys/types.h> 00014 #ifdef HAVE_UNISTD_H 00015 #include <unistd.h> 00016 #endif 00017 00018 #ifdef HAVE_GETPWENT 00019 #include <pwd.h> 00020 #endif 00021 00022 #ifdef HAVE_GETGRENT 00023 #include <grp.h> 00024 #endif 00025 00026 static VALUE sPasswd; 00027 #ifdef HAVE_GETGRENT 00028 static VALUE sGroup; 00029 #endif 00030 00031 #ifdef _WIN32 00032 #include <shlobj.h> 00033 #ifndef CSIDL_COMMON_APPDATA 00034 #define CSIDL_COMMON_APPDATA 35 00035 #endif 00036 #endif 00037 00038 #ifndef _WIN32 00039 char *getenv(); 00040 #endif 00041 char *getlogin(); 00042 00043 /* Returns the short user name of the currently logged in user. 00044 * Unfortunately, it is often rather easy to fool getlogin(). 00045 * Avoid getlogin() for security-related purposes. 00046 * 00047 * e.g. 00048 * Etc.getlogin -> 'guest' 00049 */ 00050 static VALUE 00051 etc_getlogin(VALUE obj) 00052 { 00053 char *login; 00054 00055 rb_secure(4); 00056 #ifdef HAVE_GETLOGIN 00057 login = getlogin(); 00058 if (!login) login = getenv("USER"); 00059 #else 00060 login = getenv("USER"); 00061 #endif 00062 00063 if (login) 00064 return rb_tainted_str_new2(login); 00065 return Qnil; 00066 } 00067 00068 #if defined(HAVE_GETPWENT) || defined(HAVE_GETGRENT) 00069 static VALUE 00070 safe_setup_str(const char *str) 00071 { 00072 if (str == 0) str = ""; 00073 return rb_tainted_str_new2(str); 00074 } 00075 #endif 00076 00077 #ifdef HAVE_GETPWENT 00078 static VALUE 00079 setup_passwd(struct passwd *pwd) 00080 { 00081 if (pwd == 0) rb_sys_fail("/etc/passwd"); 00082 return rb_struct_new(sPasswd, 00083 safe_setup_str(pwd->pw_name), 00084 #ifdef HAVE_ST_PW_PASSWD 00085 safe_setup_str(pwd->pw_passwd), 00086 #endif 00087 UIDT2NUM(pwd->pw_uid), 00088 GIDT2NUM(pwd->pw_gid), 00089 #ifdef HAVE_ST_PW_GECOS 00090 safe_setup_str(pwd->pw_gecos), 00091 #endif 00092 safe_setup_str(pwd->pw_dir), 00093 safe_setup_str(pwd->pw_shell), 00094 #ifdef HAVE_ST_PW_CHANGE 00095 INT2NUM(pwd->pw_change), 00096 #endif 00097 #ifdef HAVE_ST_PW_QUOTA 00098 INT2NUM(pwd->pw_quota), 00099 #endif 00100 #ifdef HAVE_ST_PW_AGE 00101 PW_AGE2VAL(pwd->pw_age), 00102 #endif 00103 #ifdef HAVE_ST_PW_CLASS 00104 safe_setup_str(pwd->pw_class), 00105 #endif 00106 #ifdef HAVE_ST_PW_COMMENT 00107 safe_setup_str(pwd->pw_comment), 00108 #endif 00109 #ifdef HAVE_ST_PW_EXPIRE 00110 INT2NUM(pwd->pw_expire), 00111 #endif 00112 0 /*dummy*/ 00113 ); 00114 } 00115 #endif 00116 00117 /* Returns the /etc/passwd information for the user with specified integer 00118 * user id (uid). 00119 * 00120 * The information is returned as a Struct::Passwd; see getpwent above for 00121 * details. 00122 * 00123 * e.g. * Etc.getpwuid(0) -> #<struct Struct::Passwd name="root", 00124 * passwd="x", uid=0, gid=0, gecos="root",dir="/root", shell="/bin/bash"> 00125 */ 00126 static VALUE 00127 etc_getpwuid(int argc, VALUE *argv, VALUE obj) 00128 { 00129 #if defined(HAVE_GETPWENT) 00130 VALUE id; 00131 rb_uid_t uid; 00132 struct passwd *pwd; 00133 00134 rb_secure(4); 00135 if (rb_scan_args(argc, argv, "01", &id) == 1) { 00136 uid = NUM2UIDT(id); 00137 } 00138 else { 00139 uid = getuid(); 00140 } 00141 pwd = getpwuid(uid); 00142 if (pwd == 0) rb_raise(rb_eArgError, "can't find user for %d", (int)uid); 00143 return setup_passwd(pwd); 00144 #else 00145 return Qnil; 00146 #endif 00147 } 00148 00149 /* Returns the /etc/passwd information for the user with specified login name. 00150 * 00151 * The information is returned as a Struct::Passwd; see getpwent above for 00152 * details. 00153 * 00154 * e.g. * Etc.getpwnam('root') -> #<struct Struct::Passwd name="root", 00155 * passwd="x", uid=0, gid=0, gecos="root",dir="/root", shell="/bin/bash"> 00156 */ 00157 static VALUE 00158 etc_getpwnam(VALUE obj, VALUE nam) 00159 { 00160 #ifdef HAVE_GETPWENT 00161 struct passwd *pwd; 00162 00163 SafeStringValue(nam); 00164 pwd = getpwnam(RSTRING_PTR(nam)); 00165 if (pwd == 0) rb_raise(rb_eArgError, "can't find user for %s", RSTRING_PTR(nam)); 00166 return setup_passwd(pwd); 00167 #else 00168 return Qnil; 00169 #endif 00170 } 00171 00172 #ifdef HAVE_GETPWENT 00173 static int passwd_blocking = 0; 00174 static VALUE 00175 passwd_ensure(void) 00176 { 00177 passwd_blocking = (int)Qfalse; 00178 return Qnil; 00179 } 00180 00181 static VALUE 00182 passwd_iterate(void) 00183 { 00184 struct passwd *pw; 00185 00186 setpwent(); 00187 while (pw = getpwent()) { 00188 rb_yield(setup_passwd(pw)); 00189 } 00190 endpwent(); 00191 return Qnil; 00192 } 00193 00194 static void 00195 each_passwd(void) 00196 { 00197 if (passwd_blocking) { 00198 rb_raise(rb_eRuntimeError, "parallel passwd iteration"); 00199 } 00200 passwd_blocking = (int)Qtrue; 00201 rb_ensure(passwd_iterate, 0, passwd_ensure, 0); 00202 } 00203 #endif 00204 00205 /* Provides a convenient Ruby iterator which executes a block for each entry 00206 * in the /etc/passwd file. 00207 * 00208 * The code block is passed an Struct::Passwd struct; see getpwent above for 00209 * details. 00210 * 00211 * Example: 00212 * 00213 * require 'etc' 00214 * 00215 * Etc.passwd {|u| 00216 * puts u.name + " = " + u.gecos 00217 * } 00218 * 00219 */ 00220 static VALUE 00221 etc_passwd(VALUE obj) 00222 { 00223 #ifdef HAVE_GETPWENT 00224 struct passwd *pw; 00225 00226 rb_secure(4); 00227 if (rb_block_given_p()) { 00228 each_passwd(); 00229 } 00230 else if (pw = getpwent()) { 00231 return setup_passwd(pw); 00232 } 00233 #endif 00234 return Qnil; 00235 } 00236 00237 /* Iterates for each entry in the /etc/passwd file if a block is given. 00238 * If no block is given, returns the enumerator. 00239 * 00240 * The code block is passed an Struct::Passwd struct; see getpwent above for 00241 * details. 00242 * 00243 * Example: 00244 * 00245 * require 'etc' 00246 * 00247 * Etc::Passwd.each {|u| 00248 * puts u.name + " = " + u.gecos 00249 * } 00250 * 00251 * Etc::Passwd.collect {|u| u.gecos} 00252 * Etc::Passwd.collect {|u| u.gecos} 00253 * 00254 */ 00255 static VALUE 00256 etc_each_passwd(VALUE obj) 00257 { 00258 #ifdef HAVE_GETPWENT 00259 RETURN_ENUMERATOR(obj, 0, 0); 00260 each_passwd(); 00261 #endif 00262 return obj; 00263 } 00264 00265 /* Resets the process of reading the /etc/passwd file, so that the next call 00266 * to getpwent will return the first entry again. 00267 */ 00268 static VALUE 00269 etc_setpwent(VALUE obj) 00270 { 00271 #ifdef HAVE_GETPWENT 00272 setpwent(); 00273 #endif 00274 return Qnil; 00275 } 00276 00277 /* Ends the process of scanning through the /etc/passwd file begun with 00278 * getpwent, and closes the file. 00279 */ 00280 static VALUE 00281 etc_endpwent(VALUE obj) 00282 { 00283 #ifdef HAVE_GETPWENT 00284 endpwent(); 00285 #endif 00286 return Qnil; 00287 } 00288 00289 /* Returns an entry from the /etc/passwd file. The first time it is called it 00290 * opens the file and returns the first entry; each successive call returns 00291 * the next entry, or nil if the end of the file has been reached. 00292 * 00293 * To close the file when processing is complete, call endpwent. 00294 * 00295 * Each entry is returned as a Struct::Passwd: 00296 * 00297 * - Passwd#name contains the short login name of the user as a String. 00298 * 00299 * - Passwd#passwd contains the encrypted password of the user as a String. 00300 * an 'x' is returned if shadow passwords are in use. An '*' is returned 00301 * if the user cannot log in using a password. 00302 * 00303 * - Passwd#uid contains the integer user ID (uid) of the user. 00304 * 00305 * - Passwd#gid contains the integer group ID (gid) of the user's primary group. 00306 * 00307 * - Passwd#gecos contains a longer String description of the user, such as 00308 * a full name. Some Unix systems provide structured information in the 00309 * gecos field, but this is system-dependent. 00310 * 00311 * - Passwd#dir contains the path to the home directory of the user as a String. 00312 * 00313 * - Passwd#shell contains the path to the login shell of the user as a String. 00314 */ 00315 static VALUE 00316 etc_getpwent(VALUE obj) 00317 { 00318 #ifdef HAVE_GETPWENT 00319 struct passwd *pw; 00320 00321 if (pw = getpwent()) { 00322 return setup_passwd(pw); 00323 } 00324 #endif 00325 return Qnil; 00326 } 00327 00328 #ifdef HAVE_GETGRENT 00329 static VALUE 00330 setup_group(struct group *grp) 00331 { 00332 VALUE mem; 00333 char **tbl; 00334 00335 mem = rb_ary_new(); 00336 tbl = grp->gr_mem; 00337 while (*tbl) { 00338 rb_ary_push(mem, safe_setup_str(*tbl)); 00339 tbl++; 00340 } 00341 return rb_struct_new(sGroup, 00342 safe_setup_str(grp->gr_name), 00343 #ifdef HAVE_ST_GR_PASSWD 00344 safe_setup_str(grp->gr_passwd), 00345 #endif 00346 GIDT2NUM(grp->gr_gid), 00347 mem); 00348 } 00349 #endif 00350 00351 /* Returns information about the group with specified integer group id (gid), 00352 * as found in /etc/group. 00353 * 00354 * The information is returned as a Struct::Group; see getgrent above for 00355 * details. 00356 * 00357 * e.g. Etc.getgrgid(100) -> #<struct Struct::Group name="users", passwd="x", 00358 * gid=100, mem=["meta", "root"]> 00359 * 00360 */ 00361 static VALUE 00362 etc_getgrgid(int argc, VALUE *argv, VALUE obj) 00363 { 00364 #ifdef HAVE_GETGRENT 00365 VALUE id; 00366 gid_t gid; 00367 struct group *grp; 00368 00369 rb_secure(4); 00370 if (rb_scan_args(argc, argv, "01", &id) == 1) { 00371 gid = NUM2GIDT(id); 00372 } 00373 else { 00374 gid = getgid(); 00375 } 00376 grp = getgrgid(gid); 00377 if (grp == 0) rb_raise(rb_eArgError, "can't find group for %d", (int)gid); 00378 return setup_group(grp); 00379 #else 00380 return Qnil; 00381 #endif 00382 } 00383 00384 /* Returns information about the group with specified String name, as found 00385 * in /etc/group. 00386 * 00387 * The information is returned as a Struct::Group; see getgrent above for 00388 * details. 00389 * 00390 * e.g. Etc.getgrnam('users') -> #<struct Struct::Group name="users", 00391 * passwd="x", gid=100, mem=["meta", "root"]> 00392 * 00393 */ 00394 static VALUE 00395 etc_getgrnam(VALUE obj, VALUE nam) 00396 { 00397 #ifdef HAVE_GETGRENT 00398 struct group *grp; 00399 00400 rb_secure(4); 00401 SafeStringValue(nam); 00402 grp = getgrnam(RSTRING_PTR(nam)); 00403 if (grp == 0) rb_raise(rb_eArgError, "can't find group for %s", RSTRING_PTR(nam)); 00404 return setup_group(grp); 00405 #else 00406 return Qnil; 00407 #endif 00408 } 00409 00410 #ifdef HAVE_GETGRENT 00411 static int group_blocking = 0; 00412 static VALUE 00413 group_ensure(void) 00414 { 00415 group_blocking = (int)Qfalse; 00416 return Qnil; 00417 } 00418 00419 static VALUE 00420 group_iterate(void) 00421 { 00422 struct group *pw; 00423 00424 setgrent(); 00425 while (pw = getgrent()) { 00426 rb_yield(setup_group(pw)); 00427 } 00428 endgrent(); 00429 return Qnil; 00430 } 00431 00432 static void 00433 each_group(void) 00434 { 00435 if (group_blocking) { 00436 rb_raise(rb_eRuntimeError, "parallel group iteration"); 00437 } 00438 group_blocking = (int)Qtrue; 00439 rb_ensure(group_iterate, 0, group_ensure, 0); 00440 } 00441 #endif 00442 00443 /* Provides a convenient Ruby iterator which executes a block for each entry 00444 * in the /etc/group file. 00445 * 00446 * The code block is passed an Struct::Group struct; see getgrent above for 00447 * details. 00448 * 00449 * Example: 00450 * 00451 * require 'etc' 00452 * 00453 * Etc.group {|g| 00454 * puts g.name + ": " + g.mem.join(', ') 00455 * } 00456 * 00457 */ 00458 static VALUE 00459 etc_group(VALUE obj) 00460 { 00461 #ifdef HAVE_GETGRENT 00462 struct group *grp; 00463 00464 rb_secure(4); 00465 if (rb_block_given_p()) { 00466 each_group(); 00467 } 00468 else if (grp = getgrent()) { 00469 return setup_group(grp); 00470 } 00471 #endif 00472 return Qnil; 00473 } 00474 00475 #ifdef HAVE_GETGRENT 00476 /* Iterates for each entry in the /etc/group file if a block is given. 00477 * If no block is given, returns the enumerator. 00478 * 00479 * The code block is passed an Struct::Group struct; see getpwent above for 00480 * details. 00481 * 00482 * Example: 00483 * 00484 * require 'etc' 00485 * 00486 * Etc::Group.each {|g| 00487 * puts g.name + ": " + g.mem.join(', ') 00488 * } 00489 * 00490 * Etc::Group.collect {|g| g.name} 00491 * Etc::Group.select {|g| !g.mem.empty?} 00492 * 00493 */ 00494 static VALUE 00495 etc_each_group(VALUE obj) 00496 { 00497 RETURN_ENUMERATOR(obj, 0, 0); 00498 each_group(); 00499 return obj; 00500 } 00501 #endif 00502 00503 /* Resets the process of reading the /etc/group file, so that the next call 00504 * to getgrent will return the first entry again. 00505 */ 00506 static VALUE 00507 etc_setgrent(VALUE obj) 00508 { 00509 #ifdef HAVE_GETGRENT 00510 setgrent(); 00511 #endif 00512 return Qnil; 00513 } 00514 00515 /* Ends the process of scanning through the /etc/group file begun by 00516 * getgrent, and closes the file. 00517 */ 00518 static VALUE 00519 etc_endgrent(VALUE obj) 00520 { 00521 #ifdef HAVE_GETGRENT 00522 endgrent(); 00523 #endif 00524 return Qnil; 00525 } 00526 00527 /* Returns an entry from the /etc/group file. The first time it is called it 00528 * opens the file and returns the first entry; each successive call returns 00529 * the next entry, or nil if the end of the file has been reached. 00530 * 00531 * To close the file when processing is complete, call endgrent. 00532 * 00533 * Each entry is returned as a Struct::Group: 00534 * 00535 * - Group#name contains the name of the group as a String. 00536 * 00537 * - Group#passwd contains the encrypted password as a String. An 'x' is 00538 * returned if password access to the group is not available; an empty 00539 * string is returned if no password is needed to obtain membership of 00540 * the group. 00541 * 00542 * - Group#gid contains the group's numeric ID as an integer. 00543 * 00544 * - Group#mem is an Array of Strings containing the short login names of the 00545 * members of the group. 00546 */ 00547 static VALUE 00548 etc_getgrent(VALUE obj) 00549 { 00550 #ifdef HAVE_GETGRENT 00551 struct group *gr; 00552 00553 if (gr = getgrent()) { 00554 return setup_group(gr); 00555 } 00556 #endif 00557 return Qnil; 00558 } 00559 00560 #define numberof(array) (sizeof(array) / sizeof(*(array))) 00561 00562 #ifdef _WIN32 00563 VALUE rb_w32_special_folder(int type); 00564 UINT rb_w32_system_tmpdir(WCHAR *path, UINT len); 00565 VALUE rb_w32_conv_from_wchar(const WCHAR *wstr, rb_encoding *enc); 00566 #endif 00567 00568 /* 00569 * Returns system configuration directory. 00570 */ 00571 static VALUE 00572 etc_sysconfdir(VALUE obj) 00573 { 00574 #ifdef _WIN32 00575 return rb_w32_special_folder(CSIDL_COMMON_APPDATA); 00576 #else 00577 return rb_filesystem_str_new_cstr(SYSCONFDIR); 00578 #endif 00579 } 00580 00581 /* 00582 * Returns system temporary directory. 00583 */ 00584 static VALUE 00585 etc_systmpdir(void) 00586 { 00587 VALUE tmpdir; 00588 #ifdef _WIN32 00589 WCHAR path[_MAX_PATH]; 00590 UINT len = rb_w32_system_tmpdir(path, numberof(path)); 00591 if (!len) return Qnil; 00592 tmpdir = rb_w32_conv_from_wchar(path, rb_filesystem_encoding()); 00593 #else 00594 tmpdir = rb_filesystem_str_new_cstr("/tmp"); 00595 #endif 00596 FL_UNSET(tmpdir, FL_TAINT|FL_UNTRUSTED); 00597 return tmpdir; 00598 } 00599 00600 /* 00601 * The etc module provides access to information from the running OS. 00602 * 00603 * Documented by mathew <meta@pobox.com>. 00604 */ 00605 void 00606 Init_etc(void) 00607 { 00608 VALUE mEtc; 00609 00610 mEtc = rb_define_module("Etc"); 00611 rb_define_module_function(mEtc, "getlogin", etc_getlogin, 0); 00612 00613 rb_define_module_function(mEtc, "getpwuid", etc_getpwuid, -1); 00614 rb_define_module_function(mEtc, "getpwnam", etc_getpwnam, 1); 00615 rb_define_module_function(mEtc, "setpwent", etc_setpwent, 0); 00616 rb_define_module_function(mEtc, "endpwent", etc_endpwent, 0); 00617 rb_define_module_function(mEtc, "getpwent", etc_getpwent, 0); 00618 rb_define_module_function(mEtc, "passwd", etc_passwd, 0); 00619 00620 rb_define_module_function(mEtc, "getgrgid", etc_getgrgid, -1); 00621 rb_define_module_function(mEtc, "getgrnam", etc_getgrnam, 1); 00622 rb_define_module_function(mEtc, "group", etc_group, 0); 00623 rb_define_module_function(mEtc, "setgrent", etc_setgrent, 0); 00624 rb_define_module_function(mEtc, "endgrent", etc_endgrent, 0); 00625 rb_define_module_function(mEtc, "getgrent", etc_getgrent, 0); 00626 rb_define_module_function(mEtc, "sysconfdir", etc_sysconfdir, 0); 00627 rb_define_module_function(mEtc, "systmpdir", etc_systmpdir, 0); 00628 00629 sPasswd = rb_struct_define("Passwd", 00630 "name", "passwd", "uid", "gid", 00631 #ifdef HAVE_ST_PW_GECOS 00632 "gecos", 00633 #endif 00634 "dir", "shell", 00635 #ifdef HAVE_ST_PW_CHANGE 00636 "change", 00637 #endif 00638 #ifdef HAVE_ST_PW_QUOTA 00639 "quota", 00640 #endif 00641 #ifdef HAVE_ST_PW_AGE 00642 "age", 00643 #endif 00644 #ifdef HAVE_ST_PW_CLASS 00645 "uclass", 00646 #endif 00647 #ifdef HAVE_ST_PW_COMMENT 00648 "comment", 00649 #endif 00650 #ifdef HAVE_ST_PW_EXPIRE 00651 "expire", 00652 #endif 00653 NULL); 00654 rb_define_const(mEtc, "Passwd", sPasswd); 00655 rb_extend_object(sPasswd, rb_mEnumerable); 00656 rb_define_singleton_method(sPasswd, "each", etc_each_passwd, 0); 00657 00658 #ifdef HAVE_GETGRENT 00659 sGroup = rb_struct_define("Group", "name", 00660 #ifdef HAVE_ST_GR_PASSWD 00661 "passwd", 00662 #endif 00663 "gid", "mem", NULL); 00664 00665 rb_define_const(mEtc, "Group", sGroup); 00666 rb_extend_object(sGroup, rb_mEnumerable); 00667 rb_define_singleton_method(sGroup, "each", etc_each_group, 0); 00668 #endif 00669 } 00670