| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 
 | 
 
 
 #include <unistd.h>
 #include <pwd.h>
 #include <crypt.h>
 #include <shadow.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <errno.h>
 #include <string.h>
 
 #define COND_RET(x, ret, msg...) \
 do {                     \
 errno = 0;\
 if(!(x)) { \
 if(errno == 0)fprintf(stderr, "%s:%d\nunmet condition:\"%s\"\n", __FILE__, __LINE__, #x); \
 else fprintf(stderr, "%s:%d\nerror: %s\nunmet condition:\"%s\"\n", __FILE__, __LINE__,strerror(errno), #x); \
 fprintf(stderr, msg);                                                                                  \
 fprintf(stderr, "\n");\
 ret \
 }    \
 } while(0)
 
 #define CHECK(x, msg...) COND_RET(x, return -1;, msg)
 #define CHECK_EXIT(x, msg...) COND_RET(x, exit(1);, msg)
 
 int main(int argc, char *argv[]) {
 char *filename = strrchr(argv[0], '/');
 if(filename == NULL) {
 filename = argv[0];
 } else {
 filename++;
 }
 if(!strcmp(filename, "sudo")) {
 CHECK_EXIT(argc >= 2, "Usage: %s [-u user] exec [args...]", argv[0]);
 uid_t user = 0;
 char *username = "root";
 char **exec = &argv[1];
 char *shadow = NULL;
 if (argv[1][0] == '-') {
 username = argv[2];
 exec = &argv[3];
 }
 struct passwd *usrpwd;
 CHECK_EXIT((usrpwd = getpwnam(username)) != NULL, "username:%s not found", username);
 user = usrpwd->pw_uid;
 shadow = usrpwd->pw_passwd;
 printf("shaowd=%s\n", shadow);
 char *pass = getpass("password:");
 CHECK_EXIT(setuid(0) != -1, "execute 'su; sudo chmod u+s %s' may fix this problem", argv[0]);
 if(!strcmp(shadow, "x")) {
 struct spwd *shadowpwd;
 CHECK_EXIT((shadowpwd = getspnam(username)) != NULL, "shadowpwd not found");
 shadow = shadowpwd->sp_pwdp;
 pass = crypt(pass, shadow);
 }
 printf("shaowd=%s, pass=%s\n", shadow, pass);
 CHECK_EXIT(!strcmp(shadow, pass), "password not match!");
 CHECK_EXIT(setuid(user) != -1, "");
 CHECK_EXIT(execvp(exec[0], exec) != -1, "");
 } else {
 struct passwd *pwd = NULL;
 uid_t uid = 0;
 if(argc > 1) {
 char *end = NULL;
 uid = strtoul(argv[1], &end, 10);
 CHECK_EXIT((end != NULL && end != argv[1]), "%s is not a number\n", argv[1]);
 }
 else {
 uid = getuid();
 }
 CHECK_EXIT((pwd = getpwuid(uid)) != NULL, "uid:%u not found", uid);
 printf("uid:%u, user:%s\n", pwd->pw_uid, pwd->pw_name);
 }
 return 0;
 }
 
 |