下面看一下boa.c里面的三个函数:create_server_socket, drop_privs和 drop_privs。这三个函数都被声明为static表示,静态函数对普通函数的区别就是他只能在当前文件中可见。
static int create_server_socket(void) { int server_s; server_s = socket(SERVER_AF, SOCK_STREAM, IPPROTO_TCP); //创建套接字SERVER_AF在compat.h中声明被声明为INET或INET6 if (server_s == -1) { DIE("unable to create socket"); } //DIE在defines.h中的宏定义为 //#define DIE(mesg) log_error_mesg(__FILE__, __LINE__, mesg), exit(1) //__FILE__和__LINE__分别表示当前文件和当前行 //log_error_mesg在log.c中有定义,向标准输出输出错误信息 /* server socket is nonblocking */ if (set_nonblock_fd(server_s) == -1) { DIE("fcntl: unable to set server socket to nonblocking"); }//把套接字设定成非阻塞的,set_nonblock_fd在defines.h中为宏替代real_set_nonblock_fd(在util.c中定义) /* close server socket on exec so cgi's can't write to it */ if (fcntl(server_s, F_SETFD, 1) == -1) { DIE("can't set close-on-exec on server socket!"); }//将文件描述符标记设定为1,当执行exec族函数时关闭套接字
/* reuse socket addr */ if ((setsockopt(server_s, SOL_SOCKET, SO_REUSEADDR, (void *) &sock_opt, sizeof (sock_opt))) == -1) { DIE("setsockopt"); }//如果sock_opt为0,充用bind中的地址? /* internet family-specific code encapsulated in bind_server() */ if (bind_server(server_s, server_ip) == -1) { DIE("unable to bind"); }//bind_server在ip.c中定义,针对ipv6和ipv4还有bsd的情况都有支持 /* listen: large number just in case your kernel is nicely tweaked */ if (listen(server_s, backlog) == -1) { DIE("unable to listen"); }//监听。。。最多的入队的链接请求数量 return server_s; }
下面来看第二个函数
drop_privs从语义上来讲是放弃一些权限,不知道为啥要这样做。。
在设计应用程序时,我们总是试图使用最小特权(least privilege)模型。,我们的应用程序只具有为完成给定任务所需的最小特权,这减少了安全性受到损害的可能性,这种安全性损害是由恶意用户试图哄骗我们的程序以未预料的方式使用特权造成的。(APUE page 193)
static void drop_privs(void) { /* give away our privs if we can */ if (getuid() == 0) { struct passwd *passwdbuf; passwdbuf = getpwuid(server_uid); if (passwdbuf == NULL) { DIE("getpwuid"); } if (initgroups(passwdbuf->pw_name, passwdbuf->pw_gid) == -1) { DIE("initgroups"); }//初始化附加组ID表? if (setgid(server_gid) == -1) { DIE("setgid"); } if (setuid(server_uid) == -1) { DIE("setuid"); }//setuid和setgid的用法类似。。。不过其背后的规则实在是太复杂。。 /* test for failed-but-return-was-successful setuid * http://www.securityportal.com/list-archive/bugtraq/2000/Jun/0101.html */ if (setuid(0) != -1) { DIE("icky Linux kernel bug!"); } } else { if (server_gid || server_uid) { log_error_time(); fprintf(stderr, "Warning: " "Not running as root: no attempt to change" " to uid %d gid %d\n", server_uid, server_gid); } server_gid = getgid(); server_uid = getuid(); }//上面两个第一次赋值我还没找到。。 }
fixup_server_root的目的就是确保服务器根目录有效
static void fixup_server_root() { char *dirbuf; if (!server_root) { #ifdef SERVER_ROOT server_root = strdup(SERVER_ROOT);//复制字符串 if (!server_root) { perror("strdup (SERVER_ROOT)"); exit(1); } #else fputs("boa: don't know where server root is. Please #define " "SERVER_ROOT in boa.h\n" "and recompile, or use the -c command line option to " "specify it.\n", stderr); exit(1); #endif } if (chdir(server_root) == -1) { fprintf(stderr, "Could not chdir to \"%s\": aborting\n", server_root); exit(1); } dirbuf = normalize_path(server_root);//在util.c中定义,转为绝对路径? free(server_root);//strdup中用的malloc分配空间 server_root = dirbuf; }