/*#define UVERBOSE*/ JNIEXPORT jobject JNICALL Java_org_tanukisoftware_wrapper_WrapperManager_nativeGetUser(JNIEnv *env, jclass clazz, jboolean groups) { jclass wrapperUserClass; jmethodID constructor; jmethodID setGroup; jmethodID addGroup; uid_t uid; struct passwd *pw; gid_t ugid; jbyteArray jUser; jbyteArray jRealName; jbyteArray jHome; jbyteArray jShell; jobject wrapperUser = NULL; struct group *aGroup; int member; int i; gid_t ggid; jbyteArray jGroupName; /* Look for the WrapperUser class. Ignore failures as JNI throws an exception. */ if ((wrapperUserClass = (*env)->FindClass(env, "org/tanukisoftware/wrapper/WrapperUNIXUser")) != NULL) { /* Look for the constructor. Ignore failures. */ if ((constructor = (*env)->GetMethodID(env, wrapperUserClass, "<init>", "(II[B[B[B[B)V")) != NULL) { uid = geteuid(); pw = getpwuid(uid); ugid = pw->pw_gid; /* Create the arguments to the constructor as java objects */ /* User byte array */ jUser = (*env)->NewByteArray(env, strlen(pw->pw_name)); (*env)->SetByteArrayRegion(env, jUser, 0, strlen(pw->pw_name), (jbyte*)pw->pw_name); /* Real Name byte array */ jRealName = (*env)->NewByteArray(env, strlen(pw->pw_gecos)); (*env)->SetByteArrayRegion(env, jRealName, 0, strlen(pw->pw_gecos), (jbyte*)pw->pw_gecos); /* Home byte array */ jHome = (*env)->NewByteArray(env, strlen(pw->pw_dir)); (*env)->SetByteArrayRegion(env, jHome, 0, strlen(pw->pw_dir), (jbyte*)pw->pw_dir); /* Shell byte array */ jShell = (*env)->NewByteArray(env, strlen(pw->pw_shell)); (*env)->SetByteArrayRegion(env, jShell, 0, strlen(pw->pw_shell), (jbyte*)pw->pw_shell); /* Now create the new wrapperUser using the constructor arguments collected above. */ wrapperUser = (*env)->NewObject(env, wrapperUserClass, constructor, uid, ugid, jUser, jRealName, jHome, jShell); /* If the caller requested the user's groups then look them up. */ if (groups) { /* Set the user group. */ if ((setGroup = (*env)->GetMethodID(env, wrapperUserClass, "setGroup", "(I[B)V")) != NULL) { if ((aGroup = getgrgid(ugid)) != NULL) { ggid = aGroup->gr_gid; /* Group name byte array */ jGroupName = (*env)->NewByteArray(env, strlen(aGroup->gr_name)); (*env)->SetByteArrayRegion(env, jGroupName, 0, strlen(aGroup->gr_name), (jbyte*)aGroup->gr_name); /* Add the group to the user. */ (*env)->CallVoidMethod(env, wrapperUser, setGroup, ggid, jGroupName); } } /* Look for the addGroup method. Ignore failures. */ if ((addGroup = (*env)->GetMethodID(env, wrapperUserClass, "addGroup", "(I[B)V")) != NULL) { setgrent(); while ((aGroup = getgrent()) != NULL) { /* Search the member list to decide whether or not the user is a member. */ member = 0; i = 0; while ((member == 0) && aGroup->gr_mem[i]) { if (strcmp(aGroup->gr_mem[i], pw->pw_name) == 0) { member = 1; } i++; } if (member) { ggid = aGroup->gr_gid; /* Group name byte array */ jGroupName = (*env)->NewByteArray(env, strlen(aGroup->gr_name)); (*env)->SetByteArrayRegion(env, jGroupName, 0, strlen(aGroup->gr_name), (jbyte*)aGroup->gr_name); /* Add the group to the user. */ (*env)->CallVoidMethod(env, wrapperUser, addGroup, ggid, jGroupName); } } endgrent(); } } } } return wrapperUser; }
static int userrc_parse(struct vboxuser *vboxuser, unsigned char *home) { unsigned char tempsectname[VBOX_MAX_RCLINE_SIZE + 1]; struct passwd *pwdent; struct group *grpent; unsigned char *varusr; unsigned char *vargrp; unsigned char *varspc; unsigned char *varmsk; int havegroup; static struct vboxrc rc_user_c[] = { { "user" , NULL }, { "group" , NULL }, { "umask" , NULL }, { "hdspace" , NULL }, { NULL , NULL } }; xstrncpy(temppathname, SYSCONFDIR , PATH_MAX); xstrncat(temppathname, "/vboxgetty.conf", PATH_MAX); xstrncpy(tempsectname, "vboxgetty-phone-" , VBOX_MAX_RCLINE_SIZE); xstrncat(tempsectname, vboxuser->localphone, VBOX_MAX_RCLINE_SIZE); if (rc_read(rc_user_c, temppathname, tempsectname) < 0) return(-1); varusr = rc_get_entry(rc_user_c, "user" ); vargrp = rc_get_entry(rc_user_c, "group" ); varspc = rc_get_entry(rc_user_c, "hdspace"); varmsk = rc_get_entry(rc_user_c, "umask" ); vboxuser->uid = 0; vboxuser->gid = 0; vboxuser->space = 0; vboxuser->umask = 0; strcpy(vboxuser->home, ""); strcpy(vboxuser->name, ""); if ((!varusr) || (!*varusr)) { log_line(LOG_E, "You *must* specify a user name or a user id!\n"); rc_free(rc_user_c); return(-1); } if (*varusr == '#') pwdent = getpwuid((uid_t)xstrtol(&varusr[1], 0)); else pwdent = getpwnam(varusr); if (!pwdent) { log_line(LOG_E, "Unable to locate \"%s\" in systems passwd list.\n", varusr); rc_free(rc_user_c); return(-1); } vboxuser->uid = pwdent->pw_uid; vboxuser->gid = pwdent->pw_gid; if ((strlen(home) + strlen(pwdent->pw_name) + 2) < (PATH_MAX - 100)) { xstrncpy(vboxuser->name, pwdent->pw_name, VBOXUSER_USERNAME); printstring(vboxuser->home, "%s/%s", home, pwdent->pw_name); } else { log_line(LOG_E, "Oops! Spool directory name and user name too long!\n"); rc_free(rc_user_c); return(-1); } if ((vargrp) && (*vargrp)) { havegroup = 0; setgrent(); while ((grpent = getgrent())) { if (*vargrp == '#') { if (grpent->gr_gid == (gid_t)xstrtol(&vargrp[1], 0)) { vboxuser->gid = grpent->gr_gid; havegroup = 1; break; } } else { if (strcmp(grpent->gr_name, vargrp) == 0) { vboxuser->gid = grpent->gr_gid; havegroup = 1; break; } } } endgrent(); if (!havegroup) { log_line(LOG_E, "Unable to locate \"%s\" in systems group list.\n", vargrp); rc_free(rc_user_c); return(-1); } } if (varspc) vboxuser->space = xstrtol(varspc, 0); if (varmsk) vboxuser->umask = xstrtoo(varmsk, 0); log_line(LOG_D, "User \"%s\" (%d.%d) [%04o] will be used...\n", vboxuser->name, vboxuser->uid, vboxuser->gid, vboxuser->umask); rc_free(rc_user_c); return(0); }
int grp_add(char *str) { u_int indx; GRPT *pt; struct group *gr; gid_t gid; /* * create the table if it doesn't exist */ if ((str == NULL) || (*str == '\0')) return(-1); if ((grptb == NULL) && ((grptb = (GRPT **)calloc(GRP_TB_SZ, sizeof(GRPT *))) == NULL)) { paxwarn(1, "Unable to allocate memory fo group selection table"); return(-1); } /* * figure out user spec */ if (str[0] != '#') { /* * it is a group name, \# escapes # as first char in group name */ if ((str[0] == '\\') && (str[1] == '#')) ++str; if ((gr = getgrnam(str)) == NULL) { paxwarn(1,"Cannot determine gid for group name: %s", str); return(-1); } gid = gr->gr_gid; } else # ifdef NET2_STAT gid = (gid_t)atoi(str+1); # else gid = (gid_t)strtoul(str+1, NULL, 10); # endif endgrent(); /* * hash it and go down the hash chain (if any) looking for it */ indx = ((unsigned)gid) % GRP_TB_SZ; if ((pt = grptb[indx]) != NULL) { while (pt != NULL) { if (pt->gid == gid) return(0); pt = pt->fow; } } /* * gid not in the table, add it to the front of the chain */ if ((pt = (GRPT *)malloc(sizeof(GRPT))) != NULL) { pt->gid = gid; pt->fow = grptb[indx]; grptb[indx] = pt; return(0); } paxwarn(1, "Group selection table out of memory"); return(-1); }
void real_endgrent() { endgrent(); }
int drop_privs(void) { struct group *gr; struct passwd *pw; char *endptr; int i; int do_setuid = 0; int do_setgid = 0; unsigned long groupid = 0; unsigned long userid = 0; if (config.group_name != NULL) { do_setgid = 1; if (!isdigit(config.group_name[0])) { gr = getgrnam(config.group_name); if(!gr){ if(config.chroot_dir){ elog("ERROR: you have chrooted and must set numeric group ID.\n"); exit(1); }else{ elog("ERROR: couldn't get ID for group %s, group does not exist.", config.group_name) exit(1); } } groupid = gr->gr_gid; } else { groupid = strtoul(config.group_name, &endptr, 10); } } if (config.user_name != NULL) { do_setuid = 1; do_setgid = 1; if (isdigit(config.user_name[0]) == 0) { pw = getpwnam(config.user_name); if (pw != NULL) { userid = pw->pw_uid; } else { printf("[E] User %s not found!\n", config.user_name); } } else { userid = strtoul(config.user_name, &endptr, 10); pw = getpwuid(userid); } if (config.group_name == NULL && pw != NULL) { groupid = pw->pw_gid; } } if (do_setgid) { if ((i = setgid(groupid)) < 0) { printf("Unable to set group ID: %s", strerror(i)); } } endgrent(); endpwent(); if (do_setuid) { if (getuid() == 0 && initgroups(config.user_name, groupid) < 0) { printf("Unable to init group names (%s/%lu)", config.user_name, groupid); } if ((i = setuid(userid)) < 0) { printf("Unable to set user ID: %s\n", strerror(i)); } } return 0; }
static void sysgroup_cleanup(void) { if (need_setent) endgrent(); }
int main (int argc, char **argv) { struct group *gr; int found = 0; int num_users, i; /* Test getgrent() without setgrent() */ for (i = 0; i < 100; i++) { gr = getgrent(); /* This is supposed to work */ #if 0 if (gr != NULL) { printf("FAIL: getgrent() with no setgrent()\n"); return 1; } #endif } /* Work out how many user till first domain group */ num_users = 0; setgrent(); while (1) { gr = getgrent(); num_users++; if (gr == NULL) break; if (strchr(gr->gr_name, '/')) { found = 1; break; } } if (!found) { printf("FAIL: could not find any domain groups\n"); return 1; } /* Test stopping getgrent in the middle of a set of users */ endgrent(); /* Test setgrent() without any getgrent() calls */ setgrent(); for (i = 0; i < (num_users - 1); i++) { getgrent(); } endgrent(); /* Test lots of setgrent() calls */ for (i = 0; i < 100; i++) { setgrent(); } /* Test lots of endgrent() calls */ for (i = 0; i < 100; i++) { endgrent(); } /* Everything's cool */ printf("PASS\n"); return 0; }
main(int argc, char *argv[]) #endif { char options[128] = "aAc:CdD::fhHI:l:L:m:M:n:p:P:qrsS:UvV-:Y:"; int arg, i, ret; int dont_fork = 0, do_help = 0; int log_set = 0; int agent_mode = -1; char *pid_file = NULL; char option_compatability[] = "-Le"; #if HAVE_GETPID int fd; FILE *PID; #endif #ifndef WIN32 /* * close all non-standard file descriptors we may have * inherited from the shell. */ for (i = getdtablesize() - 1; i > 2; --i) { (void) close(i); } #endif /* #WIN32 */ /* * register signals ASAP to prevent default action (usually core) * for signals during startup... */ #ifdef SIGTERM DEBUGMSGTL(("signal", "registering SIGTERM signal handler\n")); signal(SIGTERM, SnmpdShutDown); #endif #ifdef SIGINT DEBUGMSGTL(("signal", "registering SIGINT signal handler\n")); signal(SIGINT, SnmpdShutDown); #endif #ifdef SIGHUP signal(SIGHUP, SIG_IGN); /* do not terminate on early SIGHUP */ #endif #ifdef SIGUSR1 DEBUGMSGTL(("signal", "registering SIGUSR1 signal handler\n")); signal(SIGUSR1, SnmpdDump); #endif #ifdef SIGPIPE DEBUGMSGTL(("signal", "registering SIGPIPE signal handler\n")); signal(SIGPIPE, SIG_IGN); /* 'Inline' failure of wayward readers */ #endif #ifdef SIGXFSZ signal(SIGXFSZ, SnmpdCatchRandomSignal); #endif #ifdef NETSNMP_NO_ROOT_ACCESS /* * Default to no. */ netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS, 1); #endif /* * Default to NOT running an AgentX master. */ netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_AGENTX_MASTER, 0); netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_AGENTX_TIMEOUT, -1); netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_AGENTX_RETRIES, -1); netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_CACHE_TIMEOUT, 5); /* * Add some options if they are available. */ #if HAVE_UNISTD_H strcat(options, "g:u:"); #endif #if defined(USING_AGENTX_SUBAGENT_MODULE)|| defined(USING_AGENTX_MASTER_MODULE) strcat(options, "x:"); #endif #ifdef USING_AGENTX_SUBAGENT_MODULE strcat(options, "X"); #endif /* * This is incredibly ugly, but it's probably the simplest way * to handle the old '-L' option as well as the new '-Lx' style */ for (i=0; i<argc; i++) { if (!strcmp(argv[i], "-L")) argv[i] = option_compatability; } #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG #ifdef WIN32 snmp_log_syslogname(app_name_long); #else snmp_log_syslogname(app_name); #endif #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */ netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPTYPE, app_name); /* * Now process options normally. */ while ((arg = getopt(argc, argv, options)) != EOF) { switch (arg) { case '-': if (strcasecmp(optarg, "help") == 0) { usage(argv[0]); } if (strcasecmp(optarg, "version") == 0) { version(); } handle_long_opt(optarg); break; case 'a': log_addresses++; break; case 'A': netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPEND_LOGFILES, 1); break; case 'c': if (optarg != NULL) { netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OPTIONALCONFIG, optarg); } else { usage(argv[0]); } break; case 'C': netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_READ_CONFIGS, 1); break; case 'd': netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DUMP_PACKET, ++snmp_dump_packet); break; case 'D': #ifdef NETSNMP_DISABLE_DEBUGGING fprintf(stderr, "Debugging not configured\n"); exit(1); #else debug_register_tokens(optarg); snmp_set_do_debugging(1); #endif break; case 'f': dont_fork = 1; break; #if HAVE_UNISTD_H case 'g': if (optarg != NULL) { char *ecp; int gid; gid = strtoul(optarg, &ecp, 10); #if HAVE_GETGRNAM && HAVE_PWD_H if (*ecp) { struct group *info; info = getgrnam(optarg); gid = info ? info->gr_gid : -1; endgrent(); } #endif if (gid < 0) { fprintf(stderr, "Bad group id: %s\n", optarg); exit(1); } netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_GROUPID, gid); } else { usage(argv[0]); } break; #endif case 'h': usage(argv[0]); break; case 'H': do_help = 1; break; case 'I': if (optarg != NULL) { add_to_init_list(optarg); } else { usage(argv[0]); } break; #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE case 'l': printf("Warning: -l option is deprecated, use -Lf <file> instead\n"); if (optarg != NULL) { if (strlen(optarg) > PATH_MAX) { fprintf(stderr, "%s: logfile path too long (limit %d chars)\n", argv[0], PATH_MAX); exit(1); } snmp_enable_filelog(optarg, netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPEND_LOGFILES)); log_set = 1; } else { usage(argv[0]); } break; #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */ case 'L': if (snmp_log_options( optarg, argc, argv ) < 0 ) { usage(argv[0]); } log_set = 1; break; case 'm': if (optarg != NULL) { setenv("MIBS", optarg, 1); } else { usage(argv[0]); } break; case 'M': if (optarg != NULL) { setenv("MIBDIRS", optarg, 1); } else { usage(argv[0]); } break; case 'n': if (optarg != NULL) { app_name = optarg; netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPTYPE, app_name); } else { usage(argv[0]); } break; case 'P': printf("Warning: -P option is deprecated, use -p instead\n"); case 'p': if (optarg != NULL) { pid_file = optarg; } else { usage(argv[0]); } break; case 'q': netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_QUICK_PRINT, 1); break; case 'r': netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS); break; #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG case 's': printf("Warning: -s option is deprecated, use -Lsd instead\n"); snmp_enable_syslog(); log_set = 1; break; case 'S': printf("Warning: -S option is deprecated, use -Ls <facility> instead\n"); if (optarg != NULL) { switch (*optarg) { case 'd': case 'D': Facility = LOG_DAEMON; break; case 'i': case 'I': Facility = LOG_INFO; break; case '0': Facility = LOG_LOCAL0; break; case '1': Facility = LOG_LOCAL1; break; case '2': Facility = LOG_LOCAL2; break; case '3': Facility = LOG_LOCAL3; break; case '4': Facility = LOG_LOCAL4; break; case '5': Facility = LOG_LOCAL5; break; case '6': Facility = LOG_LOCAL6; break; case '7': Facility = LOG_LOCAL7; break; default: fprintf(stderr, "invalid syslog facility: -S%c\n",*optarg); usage(argv[0]); } snmp_enable_syslog_ident(snmp_log_syslogname(NULL), Facility); log_set = 1; } else { fprintf(stderr, "no syslog facility specified\n"); usage(argv[0]); } break; #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_SYSLOG */ case 'U': netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_LEAVE_PIDFILE); break; #if HAVE_UNISTD_H case 'u': if (optarg != NULL) { char *ecp; int uid; uid = strtoul(optarg, &ecp, 10); #if HAVE_GETPWNAM && HAVE_PWD_H if (*ecp) { struct passwd *info; info = getpwnam(optarg); uid = info ? info->pw_uid : -1; endpwent(); } #endif if (uid < 0) { fprintf(stderr, "Bad user id: %s\n", optarg); exit(1); } netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_USERID, uid); } else { usage(argv[0]); } break; #endif case 'v': version(); case 'V': netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_VERBOSE, 1); break; #if defined(USING_AGENTX_SUBAGENT_MODULE)|| defined(USING_AGENTX_MASTER_MODULE) case 'x': if (optarg != NULL) { netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_X_SOCKET, optarg); } else { usage(argv[0]); } netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_AGENTX_MASTER, 1); break; #endif case 'X': #if defined(USING_AGENTX_SUBAGENT_MODULE) agent_mode = SUB_AGENT; #else fprintf(stderr, "%s: Illegal argument -X:" "AgentX support not compiled in.\n", argv[0]); usage(argv[0]); exit(1); #endif break; case 'Y': netsnmp_config_remember(optarg); break; default: usage(argv[0]); break; } } if (do_help) { netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS, 1); init_agent(app_name); /* register our .conf handlers */ init_mib_modules(); init_snmp(app_name); fprintf(stderr, "Configuration directives understood:\n"); read_config_print_usage(" "); exit(0); } if (optind < argc) { #ifndef NETSNMP_NO_LISTEN_SUPPORT /* * There are optional transport addresses on the command line. */ DEBUGMSGTL(("snmpd/main", "optind %d, argc %d\n", optind, argc)); for (i = optind; i < argc; i++) { char *c, *astring; if ((c = netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_PORTS))) { astring = (char*)malloc(strlen(c) + 2 + strlen(argv[i])); if (astring == NULL) { fprintf(stderr, "malloc failure processing argv[%d]\n", i); exit(1); } sprintf(astring, "%s,%s", c, argv[i]); netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_PORTS, astring); SNMP_FREE(astring); } else { netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_PORTS, argv[i]); } } DEBUGMSGTL(("snmpd/main", "port spec: %s\n", netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_PORTS))); #else /* NETSNMP_NO_LISTEN_SUPPORT */ fprintf(stderr, "You specified ports to open; this agent was built to only send notifications\n"); exit(1); #endif /* NETSNMP_NO_LISTEN_SUPPORT */ } #ifdef NETSNMP_LOGFILE #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_FILE if (0 == log_set) snmp_enable_filelog(NETSNMP_LOGFILE, netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPEND_LOGFILES)); #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_FILE */ #endif #ifdef USING_UTIL_FUNCS_RESTART_MODULE { /* * Initialize a argv set to the current for restarting the agent. */ char *cptr, **argvptr; argvrestartp = (char **)malloc((argc + 2) * sizeof(char *)); argvptr = argvrestartp; for (i = 0, ret = 1; i < argc; i++) { ret += strlen(argv[i]) + 1; } argvrestart = (char *) malloc(ret); argvrestartname = (char *) malloc(strlen(argv[0]) + 1); if (!argvrestartp || !argvrestart || !argvrestartname) { fprintf(stderr, "malloc failure processing argvrestart\n"); exit(1); } strcpy(argvrestartname, argv[0]); for (cptr = argvrestart, i = 0; i < argc; i++) { strcpy(cptr, argv[i]); *(argvptr++) = cptr; cptr += strlen(argv[i]) + 1; } } #endif /* USING_UTIL_FUNCS_RESTART_MODULE */ if (agent_mode == -1) { if (strstr(argv[0], "agentxd") != NULL) { netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, SUB_AGENT); } else { netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, MASTER_AGENT); } } else { netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, agent_mode); } SOCK_STARTUP; if (init_agent(app_name) != 0) { snmp_log(LOG_ERR, "Agent initialization failed\n"); exit(1); } init_mib_modules(); /* * start library */ init_snmp(app_name); if ((ret = init_master_agent()) != 0) { /* * Some error opening one of the specified agent transports. */ snmp_log(LOG_ERR, "Server Exiting with code 1\n"); exit(1); } /* * Initialize the world. Detach from the shell. Create initial user. */ if(!dont_fork) { int quit = ! netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_QUIT_IMMEDIATELY); ret = netsnmp_daemonize(quit, #ifndef NETSNMP_FEATURE_REMOVE_LOGGING_STDIO snmp_stderrlog_status() #else /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */ 0 #endif /* NETSNMP_FEATURE_REMOVE_LOGGING_STDIO */ ); /* * xxx-rks: do we care if fork fails? I think we should... */ if(ret != 0) { snmp_log(LOG_ERR, "Server Exiting with code 1\n"); exit(1); } } #if HAVE_GETPID if (pid_file != NULL) { /* * unlink the pid_file, if it exists, prior to open. Without * doing this the open will fail if the user specified pid_file * already exists. */ unlink(pid_file); fd = open(pid_file, O_CREAT | O_EXCL | O_WRONLY, 0600); if (fd == -1) { snmp_log_perror(pid_file); if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) { exit(1); } } else { if ((PID = fdopen(fd, "w")) == NULL) { snmp_log_perror(pid_file); exit(1); } else { fprintf(PID, "%d\n", (int) getpid()); fclose(PID); } #ifndef _MSC_VER /* The sequence open()/fdopen()/fclose()/close() makes MSVC crash, hence skip the close() call when using the MSVC runtime. */ close(fd); #endif } } #endif #if defined(HAVE_UNISTD_H) && (defined(HAVE_CHOWN) || defined(HAVE_SETGID) || defined(HAVE_SETUID)) { const char *persistent_dir; int uid, gid; persistent_dir = get_persistent_directory(); mkdirhier( persistent_dir, NETSNMP_AGENT_DIRECTORY_MODE, 0 ); uid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_USERID); gid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_GROUPID); #ifdef HAVE_CHOWN if ( uid != 0 || gid != 0 ) chown( persistent_dir, uid, gid ); #endif #ifdef HAVE_SETGID if ((gid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_GROUPID)) > 0) { DEBUGMSGTL(("snmpd/main", "Changing gid to %d.\n", gid)); if (setgid(gid) == -1 #ifdef HAVE_SETGROUPS || setgroups(1, (gid_t *)&gid) == -1 #endif ) { snmp_log_perror("setgid failed"); if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) { exit(1); } } } #endif #ifdef HAVE_SETUID if ((uid = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_USERID)) > 0) { #if HAVE_GETPWNAM && HAVE_PWD_H && HAVE_INITGROUPS struct passwd *info; /* * Set supplementary groups before changing UID * (which probably involves giving up privileges) */ info = getpwuid(uid); if (info) { DEBUGMSGTL(("snmpd/main", "Supplementary groups for %s.\n", info->pw_name)); if (initgroups(info->pw_name, (gid != 0 ? (gid_t)gid : info->pw_gid)) == -1) { snmp_log_perror("initgroups failed"); if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) { exit(1); } } } endpwent(); #endif DEBUGMSGTL(("snmpd/main", "Changing uid to %d.\n", uid)); if (setuid(uid) == -1) { snmp_log_perror("setuid failed"); if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS)) { exit(1); } } } #endif } #endif /* * Store persistent data immediately in case we crash later. */ snmp_store(app_name); #ifdef SIGHUP DEBUGMSGTL(("signal", "registering SIGHUP signal handler\n")); signal(SIGHUP, SnmpdReconfig); #endif /* * Send coldstart trap if possible. */ send_easy_trap(0, 0); // 控制台对接 man_client_init(&client, &ar); swSpanningTree_module_init(&client, &ar); #if 0 int err = pthread_create(&man_thread_id, NULL, (void *)man_run, NULL); if (err != 0){ syslog(LOG_ERR, "can't create thread: %s\n", strerror(err)); return -1; } #endif /* * We're up, log our version number. */ snmp_log(LOG_INFO, "NET-SNMP version %s\n", netsnmp_get_version()); #ifdef WIN32SERVICE agent_status = AGENT_RUNNING; #endif netsnmp_addrcache_initialise(); /* * Forever monitor the dest_port for incoming PDUs. */ DEBUGMSGTL(("snmpd/main", "We're up. Starting to process data.\n")); if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_QUIT_IMMEDIATELY)) receive(); DEBUGMSGTL(("snmpd/main", "sending shutdown trap\n")); SnmpTrapNodeDown(); DEBUGMSGTL(("snmpd/main", "Bye...\n")); snmp_shutdown(app_name); shutdown_master_agent(); shutdown_agent(); if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_LEAVE_PIDFILE) && (pid_file != NULL)) { unlink(pid_file); } #ifdef WIN32SERVICE agent_status = AGENT_STOPPED; #endif #ifdef USING_UTIL_FUNCS_RESTART_MODULE SNMP_FREE(argvrestartname); SNMP_FREE(argvrestart); SNMP_FREE(argvrestartp); #endif /* USING_UTIL_FUNCS_RESTART_MODULE */ SOCK_CLEANUP; return 0; } /* End main() -- snmpd */
static int /* O - 0 = success, 1 = fail */ make_subpackage(const char *prodname, /* I - Product short name */ const char *directory, /* I - Directory for distribution files */ const char *platname, /* I - Platform name */ dist_t *dist, /* I - Distribution information */ struct utsname *platform, /* I - Platform information */ const char *subpackage) /* I - Subpackage */ { int i, j; /* Looping vars */ const char *header; /* Dependency header string */ FILE *fp; /* Control file */ char prodfull[255], /* Full name of product */ name[1024], /* Full product name */ filename[1024]; /* Destination filename */ command_t *c; /* Current command */ depend_t *d; /* Current dependency */ file_t *file; /* Current distribution file */ struct passwd *pwd; /* Pointer to user record */ struct group *grp; /* Pointer to group record */ const char *runlevels, /* Run levels */ *rlptr; /* Pointer into runlevels */ static const char *depends[] = /* Dependency names */ { "Depends:", "Conflicts:", "Replaces:", "Provides:" }; /* * Figure out the full name of the distribution... */ if (subpackage) snprintf(prodfull, sizeof(prodfull), "%s-%s", prodname, subpackage); else strlcpy(prodfull, prodname, sizeof(prodfull)); /* * Then the subdirectory name... */ if (dist->release[0]) snprintf(name, sizeof(name), "%s-%s-%s", prodfull, dist->version, dist->release); else snprintf(name, sizeof(name), "%s-%s", prodfull, dist->version); if (platname[0]) { strlcat(name, "-", sizeof(name)); strlcat(name, platname, sizeof(name)); } if (Verbosity) printf("Creating Debian %s distribution...\n", name); /* * Write the control file for DPKG... */ if (Verbosity) puts("Creating control file..."); snprintf(filename, sizeof(filename), "%s/%s", directory, name); mkdir(filename, 0777); strlcat(filename, "/DEBIAN", sizeof(filename)); mkdir(filename, 0777); chmod(filename, 0755); strlcat(filename, "/control", sizeof(filename)); if ((fp = fopen(filename, "w")) == NULL) { fprintf(stderr, "epm: Unable to create control file \"%s\" - %s\n", filename, strerror(errno)); return (1); } fprintf(fp, "Package: %s\n", prodfull); if (dist->release[0]) fprintf(fp, "Version: %s-%s\n", dist->version, dist->release); else fprintf(fp, "Version: %s\n", dist->version); fprintf(fp, "Maintainer: %s\n", dist->vendor); /* * The Architecture attribute needs to match the uname info * (which we change in get_platform to a common name) */ if (!strcmp(platform->machine, "intel")) fputs("Architecture: i386\n", fp); else if (!strcmp(platform->machine, "ppc")) fputs("Architecture: powerpc\n", fp); else fprintf(fp, "Architecture: %s\n", platform->machine); fprintf(fp, "Description: %s\n", dist->product); fprintf(fp, " Copyright: %s\n", dist->copyright); for (i = 0; i < dist->num_descriptions; i ++) if (dist->descriptions[i].subpackage == subpackage) fprintf(fp, " %s\n", dist->descriptions[i].description); for (j = DEPEND_REQUIRES; j <= DEPEND_PROVIDES; j ++) { for (i = dist->num_depends, d = dist->depends; i > 0; i --, d ++) if (d->type == j && d->subpackage == subpackage) break; if (i) { for (header = depends[j]; i > 0; i --, d ++, header = ",") if (d->type == j && d->subpackage == subpackage) { if (!strcmp(d->product, "_self")) fprintf(fp, "%s %s", header, prodname); else fprintf(fp, "%s %s", header, d->product); if (d->vernumber[0] == 0) { if (d->vernumber[1] < INT_MAX) fprintf(fp, " (<= %s)", d->version[1]); } else { if (d->vernumber[1] < INT_MAX) fprintf(fp, " (>= %s, <= %s)", d->version[0], d->version[1]); else fprintf(fp, " (>= %s)", d->version[0]); } } putc('\n', fp); } } fclose(fp); /* * Write the preinst file for DPKG... */ for (i = dist->num_commands, c = dist->commands; i > 0; i --, c ++) if (c->type == COMMAND_PRE_INSTALL && c->subpackage == subpackage) break; if (i) { if (Verbosity) puts("Creating preinst script..."); snprintf(filename, sizeof(filename), "%s/%s/DEBIAN/preinst", directory, name); if ((fp = fopen(filename, "w")) == NULL) { fprintf(stderr, "epm: Unable to create script file \"%s\" - %s\n", filename, strerror(errno)); return (1); } fchmod(fileno(fp), 0755); fputs("#!/bin/sh\n", fp); fputs("# " EPM_VERSION "\n", fp); for (; i > 0; i --, c ++) if (c->type == COMMAND_PRE_INSTALL && c->subpackage == subpackage) fprintf(fp, "%s\n", c->command); fclose(fp); } /* * Write the postinst file for DPKG... */ for (i = dist->num_commands, c = dist->commands; i > 0; i --, c ++) if (c->type == COMMAND_POST_INSTALL && c->subpackage == subpackage) break; if (!i) for (i = dist->num_files, file = dist->files; i > 0; i --, file ++) if (tolower(file->type) == 'i' && file->subpackage == subpackage) break; if (i) { if (Verbosity) puts("Creating postinst script..."); snprintf(filename, sizeof(filename), "%s/%s/DEBIAN/postinst", directory, name); if ((fp = fopen(filename, "w")) == NULL) { fprintf(stderr, "epm: Unable to create script file \"%s\" - %s\n", filename, strerror(errno)); return (1); } fchmod(fileno(fp), 0755); fputs("#!/bin/sh\n", fp); fputs("# " EPM_VERSION "\n", fp); for (i = dist->num_commands, c = dist->commands; i > 0; i --, c ++) if (c->type == COMMAND_POST_INSTALL && c->subpackage == subpackage) fprintf(fp, "%s\n", c->command); for (i = dist->num_files, file = dist->files; i > 0; i --, file ++) if (tolower(file->type) == 'i' && file->subpackage == subpackage) { runlevels = get_runlevels(file, "02345"); fprintf(fp, "update-rc.d %s start %02d", file->dst, get_start(file, 99)); for (rlptr = runlevels; isdigit(*rlptr & 255); rlptr ++) if (*rlptr != '0') fprintf(fp, " %c", *rlptr); if (strchr(runlevels, '0') != NULL) fprintf(fp, " . stop %02d 0", get_stop(file, 0)); fputs(" . >/dev/null\n", fp); fprintf(fp, "/etc/init.d/%s start\n", file->dst); } fclose(fp); } /* * Write the prerm file for DPKG... */ for (i = dist->num_commands, c = dist->commands; i > 0; i --, c ++) if (c->type == COMMAND_PRE_REMOVE && c->subpackage == subpackage) break; if (!i) for (i = dist->num_files, file = dist->files; i > 0; i --, file ++) if (tolower(file->type) == 'i' && file->subpackage == subpackage) break; if (i) { if (Verbosity) puts("Creating prerm script..."); snprintf(filename, sizeof(filename), "%s/%s/DEBIAN/prerm", directory, name); if ((fp = fopen(filename, "w")) == NULL) { fprintf(stderr, "epm: Unable to create script file \"%s\" - %s\n", filename, strerror(errno)); return (1); } fchmod(fileno(fp), 0755); fputs("#!/bin/sh\n", fp); fputs("# " EPM_VERSION "\n", fp); for (i = dist->num_commands, c = dist->commands; i > 0; i --, c ++) if (c->type == COMMAND_PRE_REMOVE && c->subpackage == subpackage) fprintf(fp, "%s\n", c->command); for (i = dist->num_files, file = dist->files; i > 0; i --, file ++) if (tolower(file->type) == 'i' && file->subpackage == subpackage) fprintf(fp, "/etc/init.d/%s stop\n", file->dst); fclose(fp); } /* * Write the postrm file for DPKG... */ for (i = dist->num_commands, c = dist->commands; i > 0; i --, c ++) if (c->type == COMMAND_POST_REMOVE && c->subpackage == subpackage) break; if (!i) for (i = dist->num_files, file = dist->files; i > 0; i --, file ++) if (tolower(file->type) == 'i' && file->subpackage == subpackage) break; if (i) { if (Verbosity) puts("Creating postrm script..."); snprintf(filename, sizeof(filename), "%s/%s/DEBIAN/postrm", directory, name); if ((fp = fopen(filename, "w")) == NULL) { fprintf(stderr, "epm: Unable to create script file \"%s\" - %s\n", filename, strerror(errno)); return (1); } fchmod(fileno(fp), 0755); fputs("#!/bin/sh\n", fp); fputs("# " EPM_VERSION "\n", fp); for (i = dist->num_commands, c = dist->commands; i > 0; i --, c ++) if (c->type == COMMAND_POST_REMOVE && c->subpackage == subpackage) fprintf(fp, "%s\n", c->command); for (i = dist->num_files, file = dist->files; i > 0; i --, file ++) if (tolower(file->type) == 'i' && file->subpackage == subpackage) { fputs("if [ purge = \"$1\" ]; then\n", fp); fprintf(fp, " update-rc.d %s remove >/dev/null\n", file->dst); fputs("fi\n", fp); } fclose(fp); } /* * Write the conffiles file for DPKG... */ if (Verbosity) puts("Creating conffiles..."); snprintf(filename, sizeof(filename), "%s/%s/DEBIAN/conffiles", directory, name); if ((fp = fopen(filename, "w")) == NULL) { fprintf(stderr, "epm: Unable to create script file \"%s\" - %s\n", filename, strerror(errno)); return (1); } for (i = dist->num_files, file = dist->files; i > 0; i --, file ++) if (tolower(file->type) == 'c' && file->subpackage == subpackage) fprintf(fp, "%s\n", file->dst); else if (tolower(file->type) == 'i' && file->subpackage == subpackage) fprintf(fp, "/etc/init.d/%s\n", file->dst); fclose(fp); /* * Copy the files over... */ if (Verbosity) puts("Copying temporary distribution files..."); for (i = dist->num_files, file = dist->files; i > 0; i --, file ++) { if (file->subpackage != subpackage) continue; /* * Find the username and groupname IDs... */ pwd = getpwnam(file->user); grp = getgrnam(file->group); endpwent(); endgrent(); /* * Copy the file or make the directory or make the symlink as needed... */ switch (tolower(file->type)) { case 'c' : case 'f' : snprintf(filename, sizeof(filename), "%s/%s%s", directory, name, file->dst); if (Verbosity > 1) printf("%s -> %s...\n", file->src, filename); if (copy_file(filename, file->src, file->mode, pwd ? pwd->pw_uid : 0, grp ? grp->gr_gid : 0)) return (1); break; case 'i' : snprintf(filename, sizeof(filename), "%s/%s/etc/init.d/%s", directory, name, file->dst); if (Verbosity > 1) printf("%s -> %s...\n", file->src, filename); if (copy_file(filename, file->src, file->mode, pwd ? pwd->pw_uid : 0, grp ? grp->gr_gid : 0)) return (1); break; case 'd' : snprintf(filename, sizeof(filename), "%s/%s%s", directory, name, file->dst); if (Verbosity > 1) printf("Directory %s...\n", filename); make_directory(filename, file->mode, pwd ? pwd->pw_uid : 0, grp ? grp->gr_gid : 0); break; case 'l' : snprintf(filename, sizeof(filename), "%s/%s%s", directory, name, file->dst); if (Verbosity > 1) printf("%s -> %s...\n", file->src, filename); make_link(filename, file->src); break; } } /* * Build the distribution from the spec file... */ if (Verbosity) printf("Building Debian %s binary distribution...\n", name); if (run_command(directory, "dpkg --build %s", name)) return (1); /* * Remove temporary files... */ if (!KeepFiles) { if (Verbosity) printf("Removing temporary %s distribution files...\n", name); snprintf(filename, sizeof(filename), "%s/%s", directory, name); unlink_directory(filename); } return (0); }
/* * login - create a new login session for a user * * login is typically called by getty as the second step of a * new user session. getty is responsible for setting the line * characteristics to a reasonable set of values and getting * the name of the user to be logged in. login may also be * called to create a new user session on a pty for a variety * of reasons, such as X servers or network logins. * * the flags which login supports are * * -p - preserve the environment * -r - perform autologin protocol for rlogin * -f - do not perform authentication, user is preauthenticated * -h - the name of the remote host */ int main (int argc, char **argv) { const char *tmptty; char tty[BUFSIZ]; #ifdef RLOGIN char term[128] = ""; #endif /* RLOGIN */ #if defined(HAVE_STRFTIME) && !defined(USE_PAM) char ptime[80]; #endif unsigned int delay; unsigned int retries; bool failed; bool subroot = false; #ifndef USE_PAM bool is_console; #endif int err; const char *cp; char *tmp; char fromhost[512]; struct passwd *pwd = NULL; char **envp = environ; const char *failent_user; /*@null@*/struct utmp *utent; #ifdef USE_PAM int retcode; pid_t child; char *pam_user = NULL; #else struct spwd *spwd = NULL; #endif /* * Some quick initialization. */ sanitize_env (); (void) setlocale (LC_ALL, ""); (void) bindtextdomain (PACKAGE, LOCALEDIR); (void) textdomain (PACKAGE); initenv (); amroot = (getuid () == 0); Prog = Basename (argv[0]); if (geteuid() != 0) { fprintf (stderr, _("%s: Cannot possibly work without effective root\n"), Prog); exit (1); } process_flags (argc, argv); if ((isatty (0) == 0) || (isatty (1) == 0) || (isatty (2) == 0)) { exit (1); /* must be a terminal */ } utent = get_current_utmp (); /* * Be picky if run by normal users (possible if installed setuid * root), but not if run by root. This way it still allows logins * even if your getty is broken, or if something corrupts utmp, * but users must "exec login" which will use the existing utmp * entry (will not overwrite remote hostname). --marekm */ if (!amroot && (NULL == utent)) { (void) puts (_("No utmp entry. You must exec \"login\" from the lowest level \"sh\"")); exit (1); } /* NOTE: utent might be NULL afterwards */ tmptty = ttyname (0); if (NULL == tmptty) { tmptty = "UNKNOWN"; } STRFCPY (tty, tmptty); #ifndef USE_PAM is_console = console (tty); #endif if (rflg || hflg) { /* * Add remote hostname to the environment. I think * (not sure) I saw it once on Irix. --marekm */ addenv ("REMOTEHOST", hostname); } if (fflg) { preauth_flag = true; } if (hflg) { reason = PW_RLOGIN; } #ifdef RLOGIN if (rflg) { assert (NULL == username); username = xmalloc (USER_NAME_MAX_LENGTH + 1); username[USER_NAME_MAX_LENGTH] = '\0'; if (do_rlogin (hostname, username, USER_NAME_MAX_LENGTH, term, sizeof term)) { preauth_flag = true; } else { free (username); username = NULL; } } #endif /* RLOGIN */ OPENLOG ("login"); setup_tty (); #ifndef USE_PAM (void) umask (getdef_num ("UMASK", GETDEF_DEFAULT_UMASK)); { /* * Use the ULIMIT in the login.defs file, and if * there isn't one, use the default value. The * user may have one for themselves, but otherwise, * just take what you get. */ long limit = getdef_long ("ULIMIT", -1L); if (limit != -1) { set_filesize_limit (limit); } } #endif /* * The entire environment will be preserved if the -p flag * is used. */ if (pflg) { while (NULL != *envp) { /* add inherited environment, */ addenv (*envp, NULL); /* some variables change later */ envp++; } } #ifdef RLOGIN if (term[0] != '\0') { addenv ("TERM", term); } else #endif /* RLOGIN */ { /* preserve TERM from getty */ if (!pflg) { tmp = getenv ("TERM"); if (NULL != tmp) { addenv ("TERM", tmp); } } } init_env (); if (optind < argc) { /* now set command line variables */ set_env (argc - optind, &argv[optind]); } if (rflg || hflg) { cp = hostname; #ifdef HAVE_STRUCT_UTMP_UT_HOST } else if ((NULL != utent) && ('\0' != utent->ut_host[0])) { cp = utent->ut_host; #endif /* HAVE_STRUCT_UTMP_UT_HOST */ } else { cp = ""; } if ('\0' != *cp) { snprintf (fromhost, sizeof fromhost, " on '%.100s' from '%.200s'", tty, cp); } else { snprintf (fromhost, sizeof fromhost, " on '%.100s'", tty); } top: /* only allow ALARM sec. for login */ (void) signal (SIGALRM, alarm_handler); timeout = getdef_unum ("LOGIN_TIMEOUT", ALARM); if (timeout > 0) { (void) alarm (timeout); } environ = newenvp; /* make new environment active */ delay = getdef_unum ("FAIL_DELAY", 1); retries = getdef_unum ("LOGIN_RETRIES", RETRIES); #ifdef USE_PAM retcode = pam_start ("login", username, &conv, &pamh); if (retcode != PAM_SUCCESS) { fprintf (stderr, _("login: PAM Failure, aborting: %s\n"), pam_strerror (pamh, retcode)); SYSLOG ((LOG_ERR, "Couldn't initialize PAM: %s", pam_strerror (pamh, retcode))); exit (99); } /* * hostname & tty are either set to NULL or their correct values, * depending on how much we know. We also set PAM's fail delay to * ours. * * PAM_RHOST and PAM_TTY are used for authentication, only use * information coming from login or from the caller (e.g. no utmp) */ retcode = pam_set_item (pamh, PAM_RHOST, hostname); PAM_FAIL_CHECK; retcode = pam_set_item (pamh, PAM_TTY, tty); PAM_FAIL_CHECK; #ifdef HAS_PAM_FAIL_DELAY retcode = pam_fail_delay (pamh, 1000000 * delay); PAM_FAIL_CHECK; #endif /* if fflg, then the user has already been authenticated */ if (!fflg) { unsigned int failcount = 0; char hostn[256]; char loginprompt[256]; /* That's one hell of a prompt :) */ /* Make the login prompt look like we want it */ if (gethostname (hostn, sizeof (hostn)) == 0) { snprintf (loginprompt, sizeof (loginprompt), _("%s login: "******"login: "******"TOO MANY LOGIN TRIES (%u)%s FOR '%s'", failcount, fromhost, failent_user)); fprintf(stderr, _("Maximum number of tries exceeded (%u)\n"), failcount); PAM_END; exit(0); } else if (retcode == PAM_ABORT) { /* Serious problems, quit now */ (void) fputs (_("login: abort requested by PAM\n"), stderr); SYSLOG ((LOG_ERR,"PAM_ABORT returned from pam_authenticate()")); PAM_END; exit(99); } else if (retcode != PAM_SUCCESS) { SYSLOG ((LOG_NOTICE,"FAILED LOGIN (%u)%s FOR '%s', %s", failcount, fromhost, failent_user, pam_strerror (pamh, retcode))); failed = true; } if (!failed) { break; } #ifdef WITH_AUDIT audit_fd = audit_open (); audit_log_acct_message (audit_fd, AUDIT_USER_LOGIN, NULL, /* Prog. name */ "login", failent_user, AUDIT_NO_ID, hostname, NULL, /* addr */ tty, 0); /* result */ close (audit_fd); #endif /* WITH_AUDIT */ (void) puts (""); (void) puts (_("Login incorrect")); if (failcount >= retries) { SYSLOG ((LOG_NOTICE, "TOO MANY LOGIN TRIES (%u)%s FOR '%s'", failcount, fromhost, failent_user)); fprintf(stderr, _("Maximum number of tries exceeded (%u)\n"), failcount); PAM_END; exit(0); } /* * Let's give it another go around. * Even if a username was given on the command * line, prompt again for the username. */ retcode = pam_set_item (pamh, PAM_USER, NULL); PAM_FAIL_CHECK; } /* We don't get here unless they were authenticated above */ (void) alarm (0); } /* Check the account validity */ retcode = pam_acct_mgmt (pamh, 0); if (retcode == PAM_NEW_AUTHTOK_REQD) { retcode = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK); } PAM_FAIL_CHECK; /* Open the PAM session */ get_pam_user (&pam_user); retcode = pam_open_session (pamh, hushed (pam_user) ? PAM_SILENT : 0); PAM_FAIL_CHECK; /* Grab the user information out of the password file for future usage * First get the username that we are actually using, though. * * From now on, we will discard changes of the user (PAM_USER) by * PAM APIs. */ get_pam_user (&pam_user); if (NULL != username) { free (username); } username = pam_user; failent_user = get_failent_user (username); pwd = xgetpwnam (username); if (NULL == pwd) { SYSLOG ((LOG_ERR, "cannot find user %s", failent_user)); exit (1); } /* This set up the process credential (group) and initialize the * supplementary group access list. * This has to be done before pam_setcred */ if (setup_groups (pwd) != 0) { exit (1); } retcode = pam_setcred (pamh, PAM_ESTABLISH_CRED); PAM_FAIL_CHECK; /* NOTE: If pam_setcred changes PAM_USER, this will not be taken * into account. */ #else /* ! USE_PAM */ while (true) { /* repeatedly get login/password pairs */ /* user_passwd is always a pointer to this constant string * or a passwd or shadow password that will be memzero by * pw_free / spw_free. * Do not free() user_passwd. */ const char *user_passwd = "!"; /* Do some cleanup to avoid keeping entries we do not need * anymore. */ if (NULL != pwd) { pw_free (pwd); pwd = NULL; } if (NULL != spwd) { spw_free (spwd); spwd = NULL; } failed = false; /* haven't failed authentication yet */ if (NULL == username) { /* need to get a login id */ if (subroot) { closelog (); exit (1); } preauth_flag = false; username = xmalloc (USER_NAME_MAX_LENGTH + 1); username[USER_NAME_MAX_LENGTH] = '\0'; login_prompt (_("\n%s login: "******"!", * the account is locked and the user cannot * login, even if they have been * "pre-authenticated." */ if ( ('!' == user_passwd[0]) || ('*' == user_passwd[0])) { failed = true; } } if (strcmp (user_passwd, SHADOW_PASSWD_STRING) == 0) { spwd = xgetspnam (username); if (NULL != spwd) { user_passwd = spwd->sp_pwdp; } else { /* The user exists in passwd, but not in * shadow. SHADOW_PASSWD_STRING indicates * that the password shall be in shadow. */ SYSLOG ((LOG_WARN, "no shadow password for '%s'%s", username, fromhost)); } } /* * The -r and -f flags provide a name which has already * been authenticated by some server. */ if (preauth_flag) { goto auth_ok; } if (pw_auth (user_passwd, username, reason, (char *) 0) == 0) { goto auth_ok; } SYSLOG ((LOG_WARN, "invalid password for '%s' %s", failent_user, fromhost)); failed = true; auth_ok: /* * This is the point where all authenticated users wind up. * If you reach this far, your password has been * authenticated and so on. */ if ( !failed && (NULL != pwd) && (0 == pwd->pw_uid) && !is_console) { SYSLOG ((LOG_CRIT, "ILLEGAL ROOT LOGIN %s", fromhost)); failed = true; } if ( !failed && !login_access (username, ('\0' != *hostname) ? hostname : tty)) { SYSLOG ((LOG_WARN, "LOGIN '%s' REFUSED %s", username, fromhost)); failed = true; } if ( (NULL != pwd) && getdef_bool ("FAILLOG_ENAB") && !failcheck (pwd->pw_uid, &faillog, failed)) { SYSLOG ((LOG_CRIT, "exceeded failure limit for '%s' %s", username, fromhost)); failed = true; } if (!failed) { break; } /* don't log non-existent users */ if ((NULL != pwd) && getdef_bool ("FAILLOG_ENAB")) { failure (pwd->pw_uid, tty, &faillog); } if (getdef_str ("FTMP_FILE") != NULL) { #ifdef USE_UTMPX struct utmpx *failent = prepare_utmpx (failent_user, tty, /* FIXME: or fromhost? */hostname, utent); #else /* !USE_UTMPX */ struct utmp *failent = prepare_utmp (failent_user, tty, hostname, utent); #endif /* !USE_UTMPX */ failtmp (failent_user, failent); free (failent); } retries--; if (retries <= 0) { SYSLOG ((LOG_CRIT, "REPEATED login failures%s", fromhost)); } /* * If this was a passwordless account and we get here, login * was denied (securetty, faillog, etc.). There was no * password prompt, so do it now (will always fail - the bad * guys won't see that the passwordless account exists at * all). --marekm */ if (user_passwd[0] == '\0') { pw_auth ("!", username, reason, (char *) 0); } /* * Authentication of this user failed. * The username must be confirmed in the next try. */ free (username); username = NULL; /* * Wait a while (a la SVR4 /usr/bin/login) before attempting * to login the user again. If the earlier alarm occurs * before the sleep() below completes, login will exit. */ if (delay > 0) { (void) sleep (delay); } (void) puts (_("Login incorrect")); /* allow only one attempt with -r or -f */ if (rflg || fflg || (retries <= 0)) { closelog (); exit (1); } } /* while (true) */ #endif /* ! USE_PAM */ assert (NULL != username); assert (NULL != pwd); (void) alarm (0); /* turn off alarm clock */ #ifndef USE_PAM /* PAM does this */ /* * porttime checks moved here, after the user has been * authenticated. now prints a message, as suggested * by Ivan Nejgebauer <*****@*****.**>. --marekm */ if ( getdef_bool ("PORTTIME_CHECKS_ENAB") && !isttytime (username, tty, time ((time_t *) 0))) { SYSLOG ((LOG_WARN, "invalid login time for '%s'%s", username, fromhost)); closelog (); bad_time_notify (); exit (1); } check_nologin (pwd->pw_uid == 0); #endif if (getenv ("IFS")) { /* don't export user IFS ... */ addenv ("IFS= \t\n", NULL); /* ... instead, set a safe IFS */ } if (pwd->pw_shell[0] == '*') { /* subsystem root */ pwd->pw_shell++; /* skip the '*' */ subsystem (pwd); /* figure out what to execute */ subroot = true; /* say I was here again */ endpwent (); /* close all of the file which were */ endgrent (); /* open in the original rooted file */ endspent (); /* system. they will be re-opened */ #ifdef SHADOWGRP endsgent (); /* in the new rooted file system */ #endif goto top; /* go do all this all over again */ } #ifdef WITH_AUDIT audit_fd = audit_open (); audit_log_acct_message (audit_fd, AUDIT_USER_LOGIN, NULL, /* Prog. name */ "login", username, AUDIT_NO_ID, hostname, NULL, /* addr */ tty, 1); /* result */ close (audit_fd); #endif /* WITH_AUDIT */ #ifndef USE_PAM /* pam_lastlog handles this */ if (getdef_bool ("LASTLOG_ENAB")) { /* give last login and log this one */ dolastlog (&ll, pwd, tty, hostname); } #endif #ifndef USE_PAM /* PAM handles this as well */ /* * Have to do this while we still have root privileges, otherwise we * don't have access to /etc/shadow. */ if (NULL != spwd) { /* check for age of password */ if (expire (pwd, spwd)) { /* The user updated her password, get the new * entries. * Use the x variants because we need to keep the * entry for a long time, and there might be other * getxxyy in between. */ pw_free (pwd); pwd = xgetpwnam (username); if (NULL == pwd) { SYSLOG ((LOG_ERR, "cannot find user %s after update of expired password", username)); exit (1); } spw_free (spwd); spwd = xgetspnam (username); } } setup_limits (pwd); /* nice, ulimit etc. */ #endif /* ! USE_PAM */ chown_tty (pwd); #ifdef USE_PAM /* * We must fork before setuid() because we need to call * pam_close_session() as root. */ (void) signal (SIGINT, SIG_IGN); child = fork (); if (child < 0) { /* error in fork() */ fprintf (stderr, _("%s: failure forking: %s"), Prog, strerror (errno)); PAM_END; exit (0); } else if (child != 0) { /* * parent - wait for child to finish, then cleanup * session */ wait (NULL); PAM_END; exit (0); } /* child */ #endif /* If we were init, we need to start a new session */ if (getppid() == 1) { setsid(); if (ioctl(0, TIOCSCTTY, 1) != 0) { fprintf (stderr, _("TIOCSCTTY failed on %s"), tty); } } /* * The utmp entry needs to be updated to indicate the new status * of the session, the new PID and SID. */ update_utmp (username, tty, hostname, utent); /* The pwd and spwd entries for the user have been copied. * * Close all the files so that unauthorized access won't occur. */ endpwent (); /* stop access to password file */ endgrent (); /* stop access to group file */ endspent (); /* stop access to shadow passwd file */ #ifdef SHADOWGRP endsgent (); /* stop access to shadow group file */ #endif /* Drop root privileges */ #ifndef USE_PAM if (setup_uid_gid (pwd, is_console)) #else /* The group privileges were already dropped. * See setup_groups() above. */ if (change_uid (pwd)) #endif { exit (1); } setup_env (pwd); /* set env vars, cd to the home dir */ #ifdef USE_PAM { const char *const *env; env = (const char *const *) pam_getenvlist (pamh); while ((NULL != env) && (NULL != *env)) { addenv (*env, NULL); env++; } } #endif (void) setlocale (LC_ALL, ""); (void) bindtextdomain (PACKAGE, LOCALEDIR); (void) textdomain (PACKAGE); if (!hushed (username)) { addenv ("HUSHLOGIN=FALSE", NULL); /* * pam_unix, pam_mail and pam_lastlog should take care of * this */ #ifndef USE_PAM motd (); /* print the message of the day */ if ( getdef_bool ("FAILLOG_ENAB") && (0 != faillog.fail_cnt)) { failprint (&faillog); /* Reset the lockout times if logged in */ if ( (0 != faillog.fail_max) && (faillog.fail_cnt >= faillog.fail_max)) { (void) puts (_("Warning: login re-enabled after temporary lockout.")); SYSLOG ((LOG_WARN, "login '%s' re-enabled after temporary lockout (%d failures)", username, (int) faillog.fail_cnt)); } } if ( getdef_bool ("LASTLOG_ENAB") && (ll.ll_time != 0)) { time_t ll_time = ll.ll_time; #ifdef HAVE_STRFTIME (void) strftime (ptime, sizeof (ptime), "%a %b %e %H:%M:%S %z %Y", localtime (&ll_time)); printf (_("Last login: %s on %s"), ptime, ll.ll_line); #else printf (_("Last login: %.19s on %s"), ctime (&ll_time), ll.ll_line); #endif #ifdef HAVE_LL_HOST /* __linux__ || SUN4 */ if ('\0' != ll.ll_host[0]) { printf (_(" from %.*s"), (int) sizeof ll.ll_host, ll.ll_host); } #endif printf (".\n"); } agecheck (spwd); mailcheck (); /* report on the status of mail */ #endif /* !USE_PAM */ } else { addenv ("HUSHLOGIN=TRUE", NULL); } ttytype (tty); (void) signal (SIGQUIT, SIG_DFL); /* default quit signal */ (void) signal (SIGTERM, SIG_DFL); /* default terminate signal */ (void) signal (SIGALRM, SIG_DFL); /* default alarm signal */ (void) signal (SIGHUP, SIG_DFL); /* added this. --marekm */ (void) signal (SIGINT, SIG_DFL); /* default interrupt signal */ if (0 == pwd->pw_uid) { SYSLOG ((LOG_NOTICE, "ROOT LOGIN %s", fromhost)); } else if (getdef_bool ("LOG_OK_LOGINS")) { SYSLOG ((LOG_INFO, "'%s' logged in %s", username, fromhost)); } closelog (); tmp = getdef_str ("FAKE_SHELL"); if (NULL != tmp) { err = shell (tmp, pwd->pw_shell, newenvp); /* fake shell */ } else { /* exec the shell finally */ err = shell (pwd->pw_shell, (char *) 0, newenvp); } return ((err == ENOENT) ? E_CMD_NOTFOUND : E_CMD_NOEXEC); }
fsnode * read_mtree(const char *fname, fsnode *node) { struct mtree_fileinfo *fi; FILE *fp; int c, error; /* We do not yet support nesting... */ assert(node == NULL); if (strcmp(fname, "-") == 0) fp = stdin; else { fp = fopen(fname, "r"); if (fp == NULL) err(1, "Can't open `%s'", fname); } error = mtree_file_push(fname, fp); if (error) goto out; bzero(&mtree_global, sizeof(mtree_global)); bzero(&mtree_global_inode, sizeof(mtree_global_inode)); mtree_global.inode = &mtree_global_inode; mtree_global_inode.nlink = 1; mtree_global_inode.st.st_nlink = 1; mtree_global_inode.st.st_atime = mtree_global_inode.st.st_ctime = mtree_global_inode.st.st_mtime = time(NULL); errors = warnings = 0; setgroupent(1); setpassent(1); mtree_root = node; mtree_current = node; do { /* Start of a new line... */ fi = SLIST_FIRST(&mtree_fileinfo); fi->line++; error = skip_over(fp, " \t"); if (error) break; c = getc(fp); if (c == EOF) { error = ferror(fp) ? errno : -1; break; } switch (c) { case '\n': /* empty line */ error = 0; break; case '#': /* comment -- skip to end of line. */ error = skip_to(fp, "\n"); if (!error) (void)getc(fp); break; case '/': /* special commands */ error = read_mtree_command(fp); break; default: /* specification */ ungetc(c, fp); error = read_mtree_spec(fp); break; } } while (!error); endpwent(); endgrent(); if (error <= 0 && (errors || warnings)) { warnx("%u error(s) and %u warning(s) in mtree manifest", errors, warnings); if (errors) exit(1); } out: if (error > 0) errc(1, error, "Error reading mtree file"); if (fp != stdin) fclose(fp); if (mtree_root != NULL) return (mtree_root); /* Handle empty specifications. */ node = create_node(".", S_IFDIR, NULL, &mtree_global); node->first = node; return (node); }
//------------------------------------------------------------------------------ // FUNCTION: checkAccess // // REMARKS: Status of context user // // PARAMETERS: [IN] filename -> file name to verify access // [IN] chkoper -> valid options: SEC_OPT_READ, // SEC_OPT_WRITE, // SEC_OPT_READ_WRITE or // SEC_OPT_EXECUTE // // RETURN: TRUE, if user have privileges, otherwise FALSE //------------------------------------------------------------------------------ Boolean NTPProviderSecurity::checkAccess(const String filename, const String chkoper) { FILE *fp; struct passwd *pwd; struct group *grp; struct stat st; int ps, opt, i, j, ct = 0, ngr = 0; ushort rt, gr, ot, trt, tgr; Boolean ok = false, isRoot = false, okUser = (secUsername.size() > 0); char buffer[500]; char *member; // Groups array Array<gid_t> grps; // store user id uid_t user_id = -1; // store group id - is there only one group id? gid_t group_id; int accessrights; String strTmp; String path; String strValue; Array<String> strCmd; Array<String> strMembers; if(okUser) { // Retrieve uid from user strValue.clear(); // Go through password entries and find the entry that matches "secUsername" pwd = getpwent(); if(pwd != NULL) { strValue.assign(pwd->pw_name); while(!String::equalNoCase(strValue, secUsername)) { pwd = getpwent(); if(pwd == NULL) break; strValue.assign(pwd->pw_name); } } // indicate that the processing of the password database is complete endpwent(); // If we didn't find the entry - just return if(strValue.size() == 0 || !String::equalNoCase(strValue, secUsername)) return ok; // DLH set the group and user id user_id = pwd->pw_uid; group_id = pwd->pw_gid; grps.clear(); isRoot = (user_id == 0); if(!isRoot) { grps.append(group_id); // Find the groups to which this user belongs and store the list in "member" strValue.clear(); // Return a pointer to the first group structure in the group database grp = getgrent(); while(grp) { i = 0; strMembers.clear(); member = grp->gr_mem[i++]; while (member) { strMembers.append(member); member = grp->gr_mem[i++]; } for(i=0; i < strMembers.size(); i++) { strValue.assign(strMembers[i]); ps = strValue.find(secUsername); if(ps >= 0) { grps.append(grp->gr_gid); break; } } // Get the next group structure grp = getgrent(); } // Indicate that the processing of the group database is complete endgrent(); } } // Build the command with path of file strCmd.clear(); ps = filename.reverseFind('/'); if(ps > 0) { path.assign(filename.subString(0, ps)); strCmd.append(path); } // Build the command to retrieve user informations strCmd.append(filename); // // Identify the type test // opt = 0; if(String::equalNoCase(chkoper, SEC_OPT_READ) || String::equalNoCase(chkoper, SEC_OPT_READ_WRITE)) opt = 1; else if(String::equalNoCase(chkoper, SEC_OPT_WRITE) || String::equalNoCase(chkoper, SEC_OPT_READ_WRITE)) opt = 2; else if(String::equalNoCase(chkoper, SEC_OPT_EXECUTE) || String::equalNoCase(chkoper, SEC_OPT_ALL)) opt = 3; // Verify permissions from directory and file name for(int i=0; i<strCmd.size(); i++) { ok = false; strTmp.assign(strCmd[i]); // The stat call gets information about the file access permissions if(stat(strTmp.getCString(), &st) == -1) return ok; // Return ok, if is invalid user_id and other permission or is root if(!okUser && st.st_basemode & 0x04 || isRoot) ok = true; else if(user_id > 0) { // Use getaccess to check permission instead of stat so that we get consistent response from OS accessrights = getaccess( strTmp.getCString(), user_id, grps.size(), grps.getData(),(void *) 0,(void *) 0); if ( accessrights == -1) // if error - just return with ok set to false return ok; // Verify status by type test switch(opt) { case 1: ok = (accessrights & R_OK); break; case 2: ok = (accessrights & W_OK); break; case 3: ok = (accessrights & X_OK); break; default: break; } } if(!ok) break; } return ok; }
static bool drop_privs() { #ifdef HAVE_MINGW if(switchuser) { logger(LOG_ERR, "%s not supported on this platform", "-U"); return false; } if(do_chroot) { logger(LOG_ERR, "%s not supported on this platform", "-R"); return false; } #else uid_t uid = 0; if(switchuser) { struct passwd *pw = getpwnam(switchuser); if(!pw) { logger(LOG_ERR, "unknown user `%s'", switchuser); return false; } uid = pw->pw_uid; if(initgroups(switchuser, pw->pw_gid) != 0 || setgid(pw->pw_gid) != 0) { logger(LOG_ERR, "System call `%s' failed: %s", "initgroups", strerror(errno)); return false; } #ifndef ANDROID // Not supported in android NDK endgrent(); endpwent(); #endif } if(do_chroot) { tzset(); /* for proper timestamps in logs */ if(chroot(confbase) != 0 || chdir("/") != 0) { logger(LOG_ERR, "System call `%s' failed: %s", "chroot", strerror(errno)); return false; } free(confbase); confbase = xstrdup(""); } if(switchuser) if(setuid(uid) != 0) { logger(LOG_ERR, "System call `%s' failed: %s", "setuid", strerror(errno)); return false; } #endif return true; }
int drop_privileges() { struct group* perm_group = 0; struct passwd* perm_user = 0; gid_t perm_gid = 0; uid_t perm_uid = 0; int gid_ok = 0; int ret = 0; if (arg_gid) { ret = 0; while ((perm_group = getgrent()) != NULL) { if (strcmp(perm_group->gr_name, arg_gid) == 0) { perm_gid = perm_group->gr_gid; ret = 1; break; } } endgrent(); if (!ret) { LOG_FATAL("Unable to determine group id, check group name."); return -1; } LOG_TRACE("Setting group id %d (%s)", (int) perm_gid, arg_gid); ret = setgid(perm_gid); if (ret == -1) { LOG_FATAL("Unable to change group id, permission denied."); return -1; } gid_ok = 1; } if (arg_uid) { ret = 0; while ((perm_user = getpwent()) != NULL) { if (strcmp(perm_user->pw_name, arg_uid) == 0) { perm_uid = perm_user->pw_uid; if (!gid_ok) perm_gid = perm_user->pw_gid; ret = 1; break; } } endpwent(); if (!ret) { LOG_FATAL("Unable to determine user id, check user name."); return -1; } if (!gid_ok) { LOG_TRACE("Setting group id %d (%s)", (int) perm_gid, arg_gid); ret = setgid(perm_gid); if (ret == -1) { LOG_FATAL("Unable to change group id, permission denied."); return -1; } } LOG_TRACE("Setting user id %d (%s)", (int) perm_uid, arg_uid); ret = setuid(perm_uid); if (ret == -1) { LOG_FATAL("Unable to change user id, permission denied."); return -1; } } return 0; }
static void listGroupsForUser(const char *name, gid_t gid, uint maxCount, Func handleNextGroup) { if (Q_UNLIKELY(maxCount == 0)) { return; } uint found = 0; #if HAVE_GETGROUPLIST QVarLengthArray<gid_t, 100> gid_buffer; gid_buffer.resize(100); int numGroups = gid_buffer.size(); int result = getgrouplist(name, gid, gid_buffer.data(), &numGroups); if (result < 0 && uint(numGroups) < maxCount) { // getgrouplist returns -1 if the buffer was too small to store all entries, the required size is in numGroups qDebug("Buffer was too small: %d, need %d", gid_buffer.size(), numGroups); gid_buffer.resize(numGroups); numGroups = gid_buffer.size(); getgrouplist(name, gid, gid_buffer.data(), &numGroups); } for (int i = 0; i < numGroups && found < maxCount; ++i) { struct group *g = getgrgid(gid_buffer[i]); // should never be null, but better be safe than crash if (g) { found++; handleNextGroup(g); } } #else // fall back to getgrent() and reading gr->gr_mem // This is slower than getgrouplist, but works as well // add the current gid, this is often not part of g->gr_mem (e.g. build.kde.org or my openSuSE 13.1 system) struct group *g = getgrgid(gid); if (g) { handleNextGroup(g); found++; if (found >= maxCount) { return; } } static const auto groupContainsUser = [](struct group * g, const char *name) -> bool { for (char **user = g->gr_mem; *user; user++) { if (strcmp(name, *user) == 0) { return true; } } return false; }; setgrent(); while ((g = getgrent())) { // don't add the current gid again if (g->gr_gid != gid && groupContainsUser(g, name)) { handleNextGroup(g); found++; if (found >= maxCount) { break; } } } endgrent(); #endif }
/* drops privileges */ int drop_privileges(char *user, char *group){ uid_t uid=-1; gid_t gid=-1; struct group *grp; struct passwd *pw; /* set effective group ID */ if(group!=NULL){ /* see if this is a group name */ if(strspn(group,"0123456789")<strlen(group)){ grp=(struct group *)getgrnam(group); if(grp!=NULL) gid=(gid_t)(grp->gr_gid); else syslog(LOG_ERR,"Warning: Could not get group entry for '%s'",group); endgrent(); } /* else we were passed the GID */ else gid=(gid_t)atoi(group); /* set effective group ID if other than current EGID */ if(gid!=getegid()){ if(setgid(gid)==-1) syslog(LOG_ERR,"Warning: Could not set effective GID=%d",(int)gid); } } /* set effective user ID */ if(user!=NULL){ /* see if this is a user name */ if(strspn(user,"0123456789")<strlen(user)){ pw=(struct passwd *)getpwnam(user); if(pw!=NULL) uid=(uid_t)(pw->pw_uid); else syslog(LOG_ERR,"Warning: Could not get passwd entry for '%s'",user); endpwent(); } /* else we were passed the UID */ else uid=(uid_t)atoi(user); /* set effective user ID if other than current EUID */ if(uid!=geteuid()){ #ifdef HAVE_INITGROUPS /* initialize supplementary groups */ if(initgroups(user,gid)==-1){ if(errno==EPERM) syslog(LOG_ERR,"Warning: Unable to change supplementary groups using initgroups()"); else{ syslog(LOG_ERR,"Warning: Possibly root user failed dropping privileges with initgroups()"); return ERROR; } } #endif if(setuid(uid)==-1) syslog(LOG_ERR,"Warning: Could not set effective UID=%d",(int)uid); } } return OK; }
void slap_init_user( char *user, char *group ) { uid_t uid = 0; gid_t gid = 0; int got_uid = 0, got_gid = 0; if ( user ) { struct passwd *pwd; if ( isdigit( (unsigned char) *user ) ) { unsigned u; got_uid = 1; if ( lutil_atou( &u, user ) != 0 ) { Debug( LDAP_DEBUG_ANY, "Unble to parse user %s\n", user, 0, 0 ); exit( EXIT_FAILURE ); } uid = (uid_t)u; #ifdef HAVE_GETPWUID pwd = getpwuid( uid ); goto did_getpw; #else free( user ); user = NULL; #endif } else { pwd = getpwnam( user ); did_getpw: if ( pwd == NULL ) { Debug( LDAP_DEBUG_ANY, "No passwd entry for user %s\n", user, 0, 0 ); exit( EXIT_FAILURE ); } if ( got_uid ) { free( user ); user = (pwd != NULL ? ch_strdup( pwd->pw_name ) : NULL); } else { got_uid = 1; uid = pwd->pw_uid; } got_gid = 1; gid = pwd->pw_gid; #ifdef HAVE_ENDPWENT endpwent(); #endif } } if ( group ) { struct group *grp; if ( isdigit( (unsigned char) *group )) { unsigned g; if ( lutil_atou( &g, group ) != 0 ) { Debug( LDAP_DEBUG_ANY, "Unble to parse group %s\n", group, 0, 0 ); exit( EXIT_FAILURE ); } gid = (uid_t)g; #ifdef HAVE_GETGRGID grp = getgrgid( gid ); goto did_group; #endif } else { grp = getgrnam( group ); if ( grp != NULL ) gid = grp->gr_gid; did_group: if ( grp == NULL ) { Debug( LDAP_DEBUG_ANY, "No group entry for group %s\n", group, 0, 0 ); exit( EXIT_FAILURE ); } } free( group ); got_gid = 1; } if ( user ) { if ( getuid() == 0 && initgroups( user, gid ) != 0 ) { Debug( LDAP_DEBUG_ANY, "Could not set the group access (gid) list\n", 0, 0, 0 ); exit( EXIT_FAILURE ); } free( user ); } #ifdef HAVE_ENDGRENT endgrent(); #endif if ( got_gid ) { if ( setgid( gid ) != 0 ) { Debug( LDAP_DEBUG_ANY, "Could not set real group id to %d\n", (int) gid, 0, 0 ); exit( EXIT_FAILURE ); } #ifdef HAVE_SETEGID if ( setegid( gid ) != 0 ) { Debug( LDAP_DEBUG_ANY, "Could not set effective group id to %d\n", (int) gid, 0, 0 ); exit( EXIT_FAILURE ); } #endif } if ( got_uid ) { if ( setuid( uid ) != 0 ) { Debug( LDAP_DEBUG_ANY, "Could not set real user id to %d\n", (int) uid, 0, 0 ); exit( EXIT_FAILURE ); } #ifdef HAVE_SETEUID if ( seteuid( uid ) != 0 ) { Debug( LDAP_DEBUG_ANY, "Could not set effective user id to %d\n", (int) uid, 0, 0 ); exit( EXIT_FAILURE ); } #endif } }
/* * process_flags - perform command line argument setting * * process_flags() interprets the command line arguments and sets the * values that the user will be created with accordingly. The values * are checked for sanity. */ static void process_flags (int argc, char **argv) { const struct group *grp; const struct passwd *pwd; const struct spwd *spwd = NULL; int anyflag = 0; int arg; if (argc == 1 || argv[argc - 1][0] == '-') usage (); if (!(pwd = getpwnam (argv[argc - 1]))) { fprintf (stderr, _("%s: user %s does not exist\n"), Prog, argv[argc - 1]); exit (E_NOTFOUND); } user_name = argv[argc - 1]; user_id = pwd->pw_uid; user_gid = pwd->pw_gid; user_comment = xstrdup (pwd->pw_gecos); user_home = xstrdup (pwd->pw_dir); user_shell = xstrdup (pwd->pw_shell); #ifdef WITH_AUDIT user_newname = user_name; user_newid = user_id; user_newgid = user_gid; user_newcomment = user_comment; user_newhome = user_home; user_newshell = user_shell; #endif #ifdef USE_NIS /* * Now make sure it isn't an NIS user. */ if (__ispwNIS ()) { char *nis_domain; char *nis_master; fprintf (stderr, _("%s: user %s is a NIS user\n"), Prog, user_name); if (!yp_get_default_domain (&nis_domain) && !yp_master (nis_domain, "passwd.byname", &nis_master)) { fprintf (stderr, _("%s: %s is the NIS master\n"), Prog, nis_master); } exit (E_NOTFOUND); } #endif if (is_shadow_pwd && (spwd = getspnam (user_name))) { user_expire = spwd->sp_expire; user_inactive = spwd->sp_inact; #ifdef WITH_AUDIT user_newexpire = user_expire; user_newinactive = user_inactive; #endif } { /* * Parse the command line options. */ int c; static struct option long_options[] = { {"append", required_argument, NULL, 'a'}, {"comment", required_argument, NULL, 'c'}, {"home", required_argument, NULL, 'd'}, {"expiredate", required_argument, NULL, 'e'}, {"inactive", required_argument, NULL, 'f'}, {"gid", required_argument, NULL, 'g'}, {"groups", required_argument, NULL, 'G'}, {"help", no_argument, NULL, 'h'}, {"login", required_argument, NULL, 'l'}, {"lock", no_argument, NULL, 'L'}, {"move-home", no_argument, NULL, 'm'}, {"non-unique", no_argument, NULL, 'o'}, {"password", required_argument, NULL, 'p'}, {"shell", required_argument, NULL, 's'}, {"uid", required_argument, NULL, 'u'}, {"unlock", no_argument, NULL, 'U'}, {NULL, 0, NULL, '\0'} }; while ((c = getopt_long (argc, argv, "ac:d:e:f:g:G:l:Lmop:s:u:U", long_options, NULL)) != -1) { switch (c) { case 'a': aflg++; break; case 'c': if (!VALID (optarg)) { fprintf (stderr, _("%s: invalid field `%s'\n"), Prog, optarg); exit (E_BAD_ARG); } #ifdef WITH_AUDIT user_newcomment = optarg; #else user_comment = optarg; #endif cflg++; break; case 'd': if (!VALID (optarg)) { fprintf (stderr, _("%s: invalid field `%s'\n"), Prog, optarg); exit (E_BAD_ARG); } dflg++; user_newhome = optarg; break; case 'e': if (*optarg) { #ifdef WITH_AUDIT user_newexpire = strtoday (optarg); if (user_newexpire == -1) { #else user_expire = strtoday (optarg); if (user_expire == -1) { #endif fprintf (stderr, _ ("%s: invalid date `%s'\n"), Prog, optarg); exit (E_BAD_ARG); } #ifdef WITH_AUDIT user_newexpire *= DAY / SCALE; #else user_expire *= DAY / SCALE; #endif } else #ifdef WITH_AUDIT user_newexpire = -1; #else user_expire = -1; #endif eflg++; break; case 'f': #ifdef WITH_AUDIT user_newinactive = get_number (optarg); #else user_inactive = get_number (optarg); #endif fflg++; break; case 'g': grp = getgr_nam_gid (optarg); if (!grp) { fprintf (stderr, _("%s: unknown group %s\n"), Prog, optarg); exit (E_NOTFOUND); } user_newgid = grp->gr_gid; gflg++; break; case 'G': if (get_groups (optarg)) exit (E_NOTFOUND); Gflg++; break; case 'l': if (!check_user_name (optarg)) { fprintf (stderr, _("%s: invalid field `%s'\n"), Prog, optarg); exit (E_BAD_ARG); } /* * If the name does not really change, we mustn't * set the flag as this will cause rather serious * problems later! */ if (strcmp (user_name, optarg)) lflg++; user_newname = optarg; break; case 'L': if (Uflg || pflg) usage (); Lflg++; break; case 'm': if (!dflg) usage (); mflg++; break; case 'o': if (!uflg) usage (); oflg++; break; case 'p': if (Lflg || Uflg) usage (); user_pass = optarg; pflg++; break; case 's': if (!VALID (optarg)) { fprintf (stderr, _("%s: invalid field `%s'\n"), Prog, optarg); exit (E_BAD_ARG); } #ifdef WITH_AUDIT user_newshell = optarg; #else user_shell = optarg; #endif sflg++; break; case 'u': user_newid = get_id (optarg); uflg++; break; case 'U': if (Lflg && pflg) usage (); Uflg++; break; default: usage (); } anyflag++; } } if (anyflag == 0) { fprintf (stderr, _("%s: no flags given\n"), Prog); exit (E_USAGE); } if (!is_shadow_pwd && (eflg || fflg)) { fprintf (stderr, _ ("%s: shadow passwords required for -e and -f\n"), Prog); exit (E_USAGE); } if (optind != argc - 1) usage (); if (aflg && (!Gflg)) { fprintf (stderr, _("%s: -a flag is ONLY allowed with the -G flag\n"), Prog); usage (); exit (E_USAGE); } if (dflg && strcmp (user_home, user_newhome) == 0) dflg = mflg = 0; if (uflg && user_id == user_newid) uflg = oflg = 0; if (lflg && getpwnam (user_newname)) { fprintf (stderr, _("%s: user %s exists\n"), Prog, user_newname); exit (E_NAME_IN_USE); } if (uflg && !oflg && getpwuid (user_newid)) { fprintf (stderr, _("%s: uid %lu is not unique\n"), Prog, (unsigned long) user_newid); exit (E_UID_IN_USE); } } /* * close_files - close all of the files that were opened * * close_files() closes all of the files that were opened for this new * user. This causes any modified entries to be written out. */ static void close_files (void) { if (!pw_close ()) { fprintf (stderr, _("%s: cannot rewrite password file\n"), Prog); fail_exit (E_PW_UPDATE); } if (is_shadow_pwd && !spw_close ()) { fprintf (stderr, _("%s: cannot rewrite shadow password file\n"), Prog); fail_exit (E_PW_UPDATE); } if (is_shadow_pwd) spw_unlock (); (void) pw_unlock (); /* * Close the DBM and/or flat files */ endpwent (); endspent (); endgrent (); #ifdef SHADOWGRP endsgent (); #endif } /* * open_files - lock and open the password files * * open_files() opens the two password files. */ static void open_files (void) { if (!pw_lock ()) { fprintf (stderr, _("%s: unable to lock password file\n"), Prog); exit (E_PW_UPDATE); } if (!pw_open (O_RDWR)) { fprintf (stderr, _("%s: unable to open password file\n"), Prog); fail_exit (E_PW_UPDATE); } if (is_shadow_pwd && !spw_lock ()) { fprintf (stderr, _("%s: cannot lock shadow password file\n"), Prog); fail_exit (E_PW_UPDATE); } if (is_shadow_pwd && !spw_open (O_RDWR)) { fprintf (stderr, _("%s: cannot open shadow password file\n"), Prog); fail_exit (E_PW_UPDATE); } } /* * usr_update - create the user entries * * usr_update() creates the password file entries for this user and * will update the group entries if required. */ static void usr_update (void) { struct passwd pwent; const struct passwd *pwd; struct spwd spent; const struct spwd *spwd = NULL; /* * Locate the entry in /etc/passwd, which MUST exist. */ pwd = pw_locate (user_name); if (!pwd) { fprintf (stderr, _("%s: %s not found in /etc/passwd\n"), Prog, user_name); fail_exit (E_NOTFOUND); } pwent = *pwd; new_pwent (&pwent); /* * Locate the entry in /etc/shadow. It doesn't have to exist, and * won't be created if it doesn't. */ if (is_shadow_pwd && (spwd = spw_locate (user_name))) { spent = *spwd; new_spent (&spent); } if (lflg || uflg || gflg || cflg || dflg || sflg || pflg || Lflg || Uflg) { if (!pw_update (&pwent)) { fprintf (stderr, _("%s: error changing password entry\n"), Prog); fail_exit (E_PW_UPDATE); } if (lflg && !pw_remove (user_name)) { fprintf (stderr, _("%s: error removing password entry\n"), Prog); fail_exit (E_PW_UPDATE); } } if (spwd && (lflg || eflg || fflg || pflg || Lflg || Uflg)) { if (!spw_update (&spent)) { fprintf (stderr, _ ("%s: error adding new shadow password entry\n"), Prog); fail_exit (E_PW_UPDATE); } if (lflg && !spw_remove (user_name)) { fprintf (stderr, _ ("%s: error removing shadow password entry\n"), Prog); fail_exit (E_PW_UPDATE); } } } /* * move_home - move the user's home directory * * move_home() moves the user's home directory to a new location. The * files will be copied if the directory cannot simply be renamed. */ static void move_home (void) { struct stat sb; if (mflg && stat (user_home, &sb) == 0) { /* * Don't try to move it if it is not a directory * (but /dev/null for example). --marekm */ if (!S_ISDIR (sb.st_mode)) return; if (access (user_newhome, F_OK) == 0) { fprintf (stderr, _("%s: directory %s exists\n"), Prog, user_newhome); fail_exit (E_HOMEDIR); } else if (rename (user_home, user_newhome)) { if (errno == EXDEV) { if (mkdir (user_newhome, sb.st_mode & 0777)) { fprintf (stderr, _ ("%s: can't create %s\n"), Prog, user_newhome); } if (chown (user_newhome, sb.st_uid, sb.st_gid)) { fprintf (stderr, _("%s: can't chown %s\n"), Prog, user_newhome); rmdir (user_newhome); fail_exit (E_HOMEDIR); } if (copy_tree (user_home, user_newhome, uflg ? user_newid : -1, gflg ? user_newgid : -1) == 0) { if (remove_tree (user_home) != 0 || rmdir (user_home) != 0) fprintf (stderr, _ ("%s: warning: failed to completely remove old home directory %s"), Prog, user_home); #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "moving home directory", user_newname, user_newid, 1); #endif return; } (void) remove_tree (user_newhome); (void) rmdir (user_newhome); } fprintf (stderr, _ ("%s: cannot rename directory %s to %s\n"), Prog, user_home, user_newhome); fail_exit (E_HOMEDIR); } #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "moving home directory", user_newname, user_newid, 1); #endif } if (uflg || gflg) { #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing home directory owner", user_newname, user_newid, 1); #endif chown (dflg ? user_newhome : user_home, uflg ? user_newid : user_id, gflg ? user_newgid : user_gid); } } /* * update_files - update the lastlog and faillog files */ static void update_files (void) { struct lastlog ll; struct faillog fl; int fd; /* * Relocate the "lastlog" entries for the user. The old entry is * left alone in case the UID was shared. It doesn't hurt anything * to just leave it be. */ if ((fd = open (LASTLOG_FILE, O_RDWR)) != -1) { lseek (fd, (off_t) user_id * sizeof ll, SEEK_SET); if (read (fd, (char *) &ll, sizeof ll) == sizeof ll) { lseek (fd, (off_t) user_newid * sizeof ll, SEEK_SET); write (fd, (char *) &ll, sizeof ll); } close (fd); } /* * Relocate the "faillog" entries in the same manner. */ if ((fd = open (FAILLOG_FILE, O_RDWR)) != -1) { lseek (fd, (off_t) user_id * sizeof fl, SEEK_SET); if (read (fd, (char *) &fl, sizeof fl) == sizeof fl) { lseek (fd, (off_t) user_newid * sizeof fl, SEEK_SET); write (fd, (char *) &fl, sizeof fl); } close (fd); } } #ifndef NO_MOVE_MAILBOX /* * This is the new and improved code to carefully chown/rename the user's * mailbox. Maybe I am too paranoid but the mail spool dir sometimes * happens to be mode 1777 (this makes mail user agents work without * being setgid mail, but is NOT recommended; they all should be fixed * to use movemail). --marekm */ static void move_mailbox (void) { const char *maildir; char mailfile[1024], newmailfile[1024]; int fd; struct stat st; maildir = getdef_str ("MAIL_DIR"); #ifdef MAIL_SPOOL_DIR if (!maildir && !getdef_str ("MAIL_FILE")) maildir = MAIL_SPOOL_DIR; #endif if (!maildir) return; /* * O_NONBLOCK is to make sure open won't hang on mandatory locks. * We do fstat/fchown to make sure there are no races (someone * replacing /var/spool/mail/luser with a hard link to /etc/passwd * between stat and chown). --marekm */ snprintf (mailfile, sizeof mailfile, "%s/%s", maildir, user_name); fd = open (mailfile, O_RDONLY | O_NONBLOCK, 0); if (fd < 0) { /* no need for warnings if the mailbox doesn't exist */ if (errno != ENOENT) perror (mailfile); return; } if (fstat (fd, &st) < 0) { perror ("fstat"); close (fd); return; } if (st.st_uid != user_id) { /* better leave it alone */ fprintf (stderr, _("%s: warning: %s not owned by %s\n"), Prog, mailfile, user_name); close (fd); return; } if (uflg) { if (fchown (fd, user_newid, (gid_t) - 1) < 0) { perror (_("failed to change mailbox owner")); } #ifdef WITH_AUDIT else { audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing mail file owner", user_newname, user_newid, 1); } #endif } close (fd); if (lflg) { snprintf (newmailfile, sizeof newmailfile, "%s/%s", maildir, user_newname); if (link (mailfile, newmailfile) || unlink (mailfile)) { perror (_("failed to rename mailbox")); } #ifdef WITH_AUDIT else { audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "changing mail file name", user_newname, user_newid, 1); } #endif } } #endif /* * main - usermod command */ int main (int argc, char **argv) { int grp_err = 0; #ifdef USE_PAM pam_handle_t *pamh = NULL; struct passwd *pampw; int retval; #endif #ifdef WITH_AUDIT audit_help_open (); #endif /* * Get my name so that I can use it to report errors. */ Prog = Basename (argv[0]); setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); sys_ngroups = sysconf (_SC_NGROUPS_MAX); user_groups = malloc ((1 + sys_ngroups) * sizeof (char *)); user_groups[0] = (char *) 0; OPENLOG ("usermod"); is_shadow_pwd = spw_file_present (); #ifdef SHADOWGRP is_shadow_grp = sgr_file_present (); #endif process_flags (argc, argv); #ifdef USE_PAM retval = PAM_SUCCESS; pampw = getpwuid (getuid ()); if (pampw == NULL) { retval = PAM_USER_UNKNOWN; } if (retval == PAM_SUCCESS) { retval = pam_start ("usermod", pampw->pw_name, &conv, &pamh); } if (retval == PAM_SUCCESS) { retval = pam_authenticate (pamh, 0); if (retval != PAM_SUCCESS) { pam_end (pamh, retval); } } if (retval == PAM_SUCCESS) { retval = pam_acct_mgmt (pamh, 0); if (retval != PAM_SUCCESS) { pam_end (pamh, retval); } } if (retval != PAM_SUCCESS) { fprintf (stderr, _("%s: PAM authentication failed\n"), Prog); exit (1); } #endif /* USE_PAM */ /* * Do the hard stuff - open the files, change the user entries, * change the home directory, then close and update the files. */ open_files (); usr_update (); nscd_flush_cache ("passwd"); nscd_flush_cache ("group"); close_files (); if (Gflg || lflg) grp_err = grp_update (); if (mflg) move_home (); #ifndef NO_MOVE_MAILBOX if (lflg || uflg) move_mailbox (); #endif if (uflg) { update_files (); /* * Change the UID on all of the files owned by `user_id' to * `user_newid' in the user's home directory. */ chown_tree (dflg ? user_newhome : user_home, user_id, user_newid, user_gid, gflg ? user_newgid : user_gid); } if (grp_err) exit (E_GRP_UPDATE); #ifdef USE_PAM if (retval == PAM_SUCCESS) pam_end (pamh, PAM_SUCCESS); #endif /* USE_PAM */ exit (E_SUCCESS); /* NOT REACHED */ }
// // Allocate and return the list of users on this system // int32_t scap_create_userlist(scap_t* handle) { uint32_t usercnt; uint32_t grpcnt; struct passwd *p; struct group *g; // // If the list of users was already allocated for this handle (for example because this is // not the first user list block), free it // if(handle->m_userlist != NULL) { scap_free_userlist(handle->m_userlist); handle->m_userlist = NULL; } // // First pass: count the number of users and the number of groups // setpwent(); p = getpwent(); for(usercnt = 0; p; p = getpwent(), usercnt++); endpwent(); setgrent(); g = getgrent(); for(grpcnt = 0; g; g = getgrent(), grpcnt++); endgrent(); // // Memory allocations // handle->m_userlist = (scap_userlist*)malloc(sizeof(scap_userlist)); if(handle->m_userlist == NULL) { snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "userlist allocation failed(1)"); return SCAP_FAILURE; } handle->m_userlist->nusers = usercnt; handle->m_userlist->ngroups = grpcnt; handle->m_userlist->totsavelen = 0; handle->m_userlist->users = (scap_userinfo*)malloc(usercnt * sizeof(scap_userinfo)); if(handle->m_userlist->users == NULL) { snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "userlist allocation failed(2)"); free(handle->m_userlist); return SCAP_FAILURE; } handle->m_userlist->groups = (scap_groupinfo*)malloc(grpcnt * sizeof(scap_groupinfo)); if(handle->m_userlist->groups == NULL) { snprintf(handle->m_lasterr, SCAP_LASTERR_SIZE, "grouplist allocation failed(2)"); free(handle->m_userlist->users); free(handle->m_userlist); return SCAP_FAILURE; } // // Second pass: copy the data // //users setpwent(); p = getpwent(); for(usercnt = 0; p; p = getpwent(), usercnt++) { handle->m_userlist->users[usercnt].uid = p->pw_uid; handle->m_userlist->users[usercnt].gid = p->pw_gid; if(p->pw_name) { strncpy(handle->m_userlist->users[usercnt].name, p->pw_name, sizeof(handle->m_userlist->users[usercnt].name)); } else { *handle->m_userlist->users[usercnt].name = '\0'; } if(p->pw_dir) { strncpy(handle->m_userlist->users[usercnt].homedir, p->pw_dir, sizeof(handle->m_userlist->users[usercnt].homedir)); } else { *handle->m_userlist->users[usercnt].homedir = '\0'; } if(p->pw_shell) { strncpy(handle->m_userlist->users[usercnt].shell, p->pw_shell, sizeof(handle->m_userlist->users[usercnt].shell)); } else { *handle->m_userlist->users[usercnt].shell = '\0'; } handle->m_userlist->totsavelen += sizeof(uint8_t) + // type sizeof(uint32_t) + // uid sizeof(uint32_t) + // gid strlen(handle->m_userlist->users[usercnt].name) + 2 + strlen(handle->m_userlist->users[usercnt].homedir) + 2 + strlen(handle->m_userlist->users[usercnt].shell) + 2; } endpwent(); // groups setgrent(); g = getgrent(); for(grpcnt = 0; g; g = getgrent(), grpcnt++) { handle->m_userlist->groups[grpcnt].gid = g->gr_gid; if(g->gr_name) { strncpy(handle->m_userlist->groups[grpcnt].name, g->gr_name, sizeof(handle->m_userlist->groups[grpcnt].name)); } else { *handle->m_userlist->groups[grpcnt].name = '\0'; } handle->m_userlist->totsavelen += sizeof(uint8_t) + // type sizeof(uint32_t) + // gid strlen(handle->m_userlist->groups[grpcnt].name) + 2; } endgrent(); return SCAP_SUCCESS; }
static int update_group (void) { int is_member; int was_member; int changed; const struct group *grp; struct group *ngrp; /* * Lock and open the group file. This will load all of the group * entries. */ if (!gr_lock ()) { fprintf (stderr, _("%s: error locking group file\n"), Prog); SYSLOG ((LOG_ERR, "error locking group file")); return -1; } if (!gr_open (O_RDWR)) { fprintf (stderr, _("%s: error opening group file\n"), Prog); SYSLOG ((LOG_ERR, "error opening group file")); gr_unlock (); return -1; } changed = 0; /* * Scan through the entire group file looking for the groups that * the user is a member of. */ while ((grp = gr_next ())) { /* * See if the user specified this group as one of their * concurrent groups. */ was_member = is_on_list (grp->gr_mem, user_name); is_member = Gflg && is_on_list (user_groups, grp->gr_name); if (!was_member && !is_member) continue; ngrp = __gr_dup (grp); if (!ngrp) { fprintf (stderr, _("%s: out of memory in update_group\n"), Prog); gr_unlock (); return -1; } if (was_member && (!Gflg || is_member)) { if (lflg) { ngrp->gr_mem = del_list (ngrp->gr_mem, user_name); ngrp->gr_mem = add_list (ngrp->gr_mem, user_newname); changed = 1; SYSLOG ((LOG_INFO, "change `%s' to `%s' in group `%s'", user_name, user_newname, ngrp->gr_name)); } } else if (was_member && Gflg && !is_member) { ngrp->gr_mem = del_list (ngrp->gr_mem, user_name); changed = 1; SYSLOG ((LOG_INFO, "delete `%s' from group `%s'", user_name, ngrp->gr_name)); } else if (!was_member && Gflg && is_member) { ngrp->gr_mem = add_list (ngrp->gr_mem, lflg ? user_newname : user_name); changed = 1; SYSLOG ((LOG_INFO, "add `%s' to group `%s'", lflg ? user_newname : user_name, ngrp->gr_name)); } if (!changed) continue; changed = 0; if (!gr_update (ngrp)) { fprintf (stderr, _("%s: error adding new group entry\n"), Prog); SYSLOG ((LOG_ERR, "error adding group entry")); gr_unlock (); return -1; } #ifdef NDBM /* * Update the DBM group file with the new entry as well. */ if (!gr_dbm_update (ngrp)) { fprintf (stderr, _("%s: cannot add new dbm group entry\n"), Prog); SYSLOG ((LOG_ERR, "error adding dbm group entry")); gr_unlock (); return -1; } #endif /* NDBM */ } #ifdef NDBM endgrent (); #endif /* NDBM */ if (!gr_close ()) { fprintf (stderr, _("%s: cannot rewrite group file\n"), Prog); gr_unlock (); return -1; } gr_unlock (); return 0; }
static int findgroupbyname(const char *name, struct group *grp, char *buf, size_t buflen, struct group **result) { int rc; # if defined(WITH_PAM_USER_LOOKUP) || \ ( defined(WITH_FILE_USER_LOOKUP) && \ !( defined(HAVE_FGETGRENT_R) && defined(HAVE_FGETPWENT_R) ) ) rc = pthread_mutex_lock( &pw_gr_serializer ); if( rc != 0 ) return ENOENT; # endif # if defined(WITH_PAM_USER_LOOKUP) setgrent(); # if defined(HAVE_GETGRGID_R) rc = getgrnam_r( name, grp, buf, buflen, result ); # elif defined(HAVE_GETGRGID) # error non-reentrant function support using getgrgid() currently not implemented # else # error neither getgrgid_r() nor getgrgid() available # endif endgrent(); # elif defined(WITH_FILE_USER_LOOKUP) if( name == 0 ) { if( result ) *result = 0; rc = ENOENT; } else { FILE *fp = fopen( "/etc/group", "r" ); if( 0 == fp ) { rc = errno; } else { # if defined(HAVE_FGETGRENT_R) while( 0 == ( rc = fgetgrent_r( fp, grp, buf, buflen, result ) ) ) { if( (grp->gr_name != 0) && strcmp( name, grp->gr_name ) == 0 ) break; } if( ( rc != 0 ) && ( result != 0 ) ) *result = 0; # elif defined(HAVE_FGETGRENT) # error non-reentrant function support using fgetgrent() currently not implemented # else # error neither fgetgrent_r() nor fgetgrent() available # endif fclose( fp ); } } # endif # if defined(WITH_PAM_USER_LOOKUP) || \ ( defined(WITH_FILE_USER_LOOKUP) && \ !( defined(HAVE_FGETGRENT_R) && defined(HAVE_FGETPWENT_R) ) ) pthread_mutex_unlock( &pw_gr_serializer ); # endif return rc; }
int MOSGetGListFromUName( char *UName, /* I */ char *Buf, /* O (optional) */ int *GList, /* O (optional) - terminated w/-1 */ int BufSize, /* I */ int *GCount) /* I (optional) */ { char *BPtr = NULL; int BSpace = 0; struct group *GPtr; int uindex; int gindex; char GName[MMAX_NAME]; if ((UName == NULL) || (MSched.OSCredLookup == mapNever)) { return(FAILURE); } /* FORMAT: <GNAME>[,<GNAME>]... */ if (Buf != NULL) MUSNInit(&BPtr,&BSpace,Buf,BufSize); gindex = MUGIDFromUser(-1,UName,GName); if (GList != NULL) GList[0] = gindex; if (Buf != NULL) { MUSNPrintF(&BPtr,&BSpace,"%s", GName); } setgrent(); /* walk all groups, walk all users in each group (less efficient) */ gindex = 1; while ((GPtr = getgrent()) != NULL) { for (uindex = 0;GPtr->gr_mem[uindex] != NULL;uindex++) { if (!strcmp(GPtr->gr_mem[uindex],UName)) { if (Buf != NULL) { if (BPtr > Buf) MUSNCat(&BPtr,&BSpace,","); MUSNPrintF(&BPtr,&BSpace,"%s", GPtr->gr_name); } else { if (GList != NULL) GList[gindex] = GPtr->gr_gid; gindex++; if (gindex >= (BufSize - 1)) break; } break; } } /* END for (uindex) */ } /* END while (getgrent() != NULL) */ endgrent(); if (GList != NULL) GList[gindex] = -1; if (GCount != NULL) *GCount = gindex; return(SUCCESS); } /* END MOSGetGListFromUName() */
static char *validate_group(char *group, DATA_BLOB password,int snum) { #ifdef HAVE_NETGROUP { char *host, *user, *domain; setnetgrent(group); while (getnetgrent(&host, &user, &domain)) { if (user) { if (user_ok(user, snum) && password_ok(user,password)) { endnetgrent(); return(user); } } } endnetgrent(); } #endif #ifdef HAVE_GETGRENT { struct group *gptr; setgrent(); while ((gptr = (struct group *)getgrent())) { if (strequal(gptr->gr_name,group)) break; } /* * As user_ok can recurse doing a getgrent(), we must * copy the member list onto the heap before * use. Bug pointed out by [email protected]. */ if (gptr) { char *member_list = NULL; size_t list_len = 0; char *member; int i; for(i = 0; gptr->gr_mem && gptr->gr_mem[i]; i++) { list_len += strlen(gptr->gr_mem[i])+1; } list_len++; member_list = (char *)SMB_MALLOC(list_len); if (!member_list) { endgrent(); return NULL; } *member_list = '\0'; member = member_list; for(i = 0; gptr->gr_mem && gptr->gr_mem[i]; i++) { size_t member_len = strlen(gptr->gr_mem[i])+1; DEBUG(10,("validate_group: = gr_mem = " "%s\n", gptr->gr_mem[i])); safe_strcpy(member, gptr->gr_mem[i], list_len - (member-member_list)); member += member_len; } endgrent(); member = member_list; while (*member) { if (user_ok(member,snum) && password_ok(member,password)) { char *name = talloc_strdup(talloc_tos(), member); SAFE_FREE(member_list); return name; } DEBUG(10,("validate_group = member = %s\n", member)); member += strlen(member) + 1; } SAFE_FREE(member_list); } else { endgrent(); return NULL; } } #endif return(NULL); }
int main(int argc, char **argv) { struct fstab *fs; struct passwd *pw; struct group *gr; int gflag = 0, uflag = 0, errs = 0; long i, argnum, done = 0; char ch, *qfnp; while ((ch = getopt(argc, argv, "aguv")) != -1) { switch(ch) { case 'a': aflag++; break; case 'g': gflag++; break; case 'u': uflag++; break; case 'v': vflag++; break; default: usage(); } } argc -= optind; argv += optind; if (argc == 0 && !aflag) usage(); if (!gflag && !uflag) { if (aflag) gflag++; uflag++; } if (gflag) { setgrent(); while ((gr = getgrent()) != 0) addid((u_long)gr->gr_gid, GRPQUOTA, gr->gr_name); endgrent(); } if (uflag) { setpwent(); while ((pw = getpwent()) != 0) addid((u_long)pw->pw_uid, USRQUOTA, pw->pw_name); endpwent(); } setfsent(); while ((fs = getfsent()) != NULL) { if (strcmp(fs->fs_vfstype, "ufs")) continue; if (aflag) { if (gflag && hasquota(fs, GRPQUOTA, &qfnp)) errs += repquota(fs, GRPQUOTA, qfnp); if (uflag && hasquota(fs, USRQUOTA, &qfnp)) errs += repquota(fs, USRQUOTA, qfnp); continue; } if ((argnum = oneof(fs->fs_file, argv, argc)) >= 0 || (argnum = oneof(fs->fs_spec, argv, argc)) >= 0) { done |= 1 << argnum; if (gflag && hasquota(fs, GRPQUOTA, &qfnp)) errs += repquota(fs, GRPQUOTA, qfnp); if (uflag && hasquota(fs, USRQUOTA, &qfnp)) errs += repquota(fs, USRQUOTA, qfnp); } } endfsent(); for (i = 0; i < argc; i++) if ((done & (1 << i)) == 0) warnx("%s not found in fstab", argv[i]); exit(errs); }
int main(int argc, const char *argv[]) { struct passwd *pw; struct group *gp; int current_user = 0; uid_t id; int i; if (argc > 2) usage(1, NULL); if (argc == 1) { id = getuid(); current_user = 1; if (!(pw = getpwuid(id))) usage(1, "Username does not exist"); } else { if (!(pw = getpwnam(argv[1]))) usage(1, "Username does not exist"); id = pw->pw_uid; } printf("uid=%d(%s)", id, pw->pw_name); if ((gp = getgrgid(pw->pw_gid))) printf(" gid=%d(%s)", pw->pw_gid, gp->gr_name); if (current_user) { gid_t *gid_list; int gid_size; if (getuid() != geteuid()) { id = geteuid(); if (!(pw = getpwuid(id))) usage(1, "Username does not exist"); printf(" euid=%d(%s)", id, pw->pw_name); } if (getgid() != getegid()) { id = getegid(); if (!(gp = getgrgid(id))) usage(1, "Group does not exist"); printf(" egid=%d(%s)", id, gp->gr_name); } /* use getgroups interface to get current groups */ gid_size = getgroups(0, NULL); if (gid_size) { gid_list = malloc(gid_size * sizeof(gid_t)); getgroups(gid_size, gid_list); for (i = 0; i < gid_size; i++) { if (!(gp = getgrgid(gid_list[i]))) die("Group does not exist"); printf("%s%d(%s)", (i == 0) ? " groups=" : ",", gp->gr_gid, gp->gr_name); } free(gid_list); } } else { /* get list of groups from group database */ i = 0; while ((gp = getgrent())) { char *c = *(gp->gr_mem); while (c && *c) { if (!strncmp(c, pw->pw_name, 16)) { printf("%s%d(%s)", (i++ == 0) ? " groups=" : ",", gp->gr_gid, gp->gr_name); c = NULL; } else { c++; } } } endgrent(); } printf("\n"); exit(0); }
KDModule::KDModule(QWidget *parent, const char *name, const QStringList &) : KCModule(KDMFactory::instance(), parent, name) , minshowuid(0) , maxshowuid(0) , updateOK(false) { KAboutData *about = new KAboutData(I18N_NOOP("kcmkdm"), I18N_NOOP("KDE Login Manager Config Module"), 0, 0, KAboutData::License_GPL, I18N_NOOP("(c) 1996 - 2005 The KDM Authors")); about->addAuthor("Thomas Tanghus", I18N_NOOP("Original author"), "*****@*****.**"); about->addAuthor("Steffen Hansen", 0, "*****@*****.**"); about->addAuthor("Oswald Buddenhagen", I18N_NOOP("Current maintainer"), "*****@*****.**"); setQuickHelp( i18n( "<h1>Login Manager</h1> In this module you can configure the " "various aspects of the KDE Login Manager. This includes " "the look and feel as well as the users that can be " "selected for login. Note that you can only make changes " "if you run the module with superuser rights. If you have not started the KDE " "Control Center with superuser rights (which is absolutely the right thing to " "do, by the way), click on the <em>Modify</em> button to acquire " "superuser rights. You will be asked for the superuser password." "<h2>Appearance</h2> On this tab page, you can configure how " "the Login Manager should look, which language it should use, and which " "GUI style it should use. The language settings made here have no influence on " "the user's language settings." "<h2>Font</h2>Here you can choose the fonts that the Login Manager should use " "for various purposes like greetings and user names. " "<h2>Background</h2>If you want to set a special background for the login " "screen, this is where to do it." "<h2>Shutdown</h2> Here you can specify who is allowed to shutdown/reboot the machine " "and whether a boot manager should be used." "<h2>Users</h2>On this tab page, you can select which users the Login Manager " "will offer you for logging in." "<h2>Convenience</h2> Here you can specify a user to be logged in automatically, " "users not needing to provide a password to log in, and other convenience features.<br>" "Note, that these settings are security holes by their nature, so use them very carefully.")); setAboutData( about ); setlocale( LC_COLLATE, "C" ); KGlobal::locale()->insertCatalogue("kcmbackground"); QStringList sl; QMap<gid_t,QStringList> tgmap; QMap<gid_t,QStringList>::Iterator tgmapi; QMap<gid_t,QStringList>::ConstIterator tgmapci; QMap<QString, QPair<int,QStringList> >::Iterator umapi; struct passwd *ps; for (setpwent(); (ps = getpwent()); ) { QString un( QFile::decodeName( ps->pw_name ) ); if (usermap.find( un ) == usermap.end()) { usermap.insert( un, QPair<int,QStringList>( ps->pw_uid, sl ) ); if ((tgmapi = tgmap.find( ps->pw_gid )) != tgmap.end()) (*tgmapi).append( un ); else tgmap[ps->pw_gid] = un; } } endpwent(); struct group *grp; for (setgrent(); (grp = getgrent()); ) { QString gn( QFile::decodeName( grp->gr_name ) ); bool delme = false; if ((tgmapi = tgmap.find( grp->gr_gid )) != tgmap.end()) { if ((*tgmapi).count() == 1 && (*tgmapi).first() == gn) delme = true; else for (QStringList::ConstIterator it = (*tgmapi).begin(); it != (*tgmapi).end(); ++it) usermap[*it].second.append( gn ); tgmap.remove( tgmapi ); } if (!*grp->gr_mem || (delme && !grp->gr_mem[1] && gn == QFile::decodeName( *grp->gr_mem ))) continue; do { QString un( QFile::decodeName( *grp->gr_mem ) ); if ((umapi = usermap.find( un )) != usermap.end()) { if ((*umapi).second.find( gn ) == (*umapi).second.end()) (*umapi).second.append( gn ); } else kdWarning() << "group '" << gn << "' contains unknown user '" << un << "'" << endl; } while (*++grp->gr_mem); } endgrent(); for (tgmapci = tgmap.begin(); tgmapci != tgmap.end(); ++tgmapci) kdWarning() << "user(s) '" << tgmapci.data().join(",") << "' have unknown GID " << tgmapci.key() << endl; config = new KSimpleConfig( QString::fromLatin1( KDE_CONFDIR "/kdm/kdmrc" )); QVBoxLayout *top = new QVBoxLayout(this); tab = new QTabWidget(this); // ***** // _don't_ add a theme configurator until the theming engine is _really_ done!! // ***** appearance = new KDMAppearanceWidget(this); tab->addTab(appearance, i18n("A&ppearance")); connect(appearance, SIGNAL(changed(bool)), SIGNAL( changed(bool))); font = new KDMFontWidget(this); tab->addTab(font, i18n("&Font")); connect(font, SIGNAL(changed(bool)), SIGNAL(changed(bool))); background = new KBackground(this); tab->addTab(background, i18n("&Background")); connect(background, SIGNAL(changed(bool)), SIGNAL(changed(bool))); sessions = new KDMSessionsWidget(this); tab->addTab(sessions, i18n("&Shutdown")); connect(sessions, SIGNAL(changed(bool)), SIGNAL(changed(bool))); users = new KDMUsersWidget(this, 0); tab->addTab(users, i18n("&Users")); connect(users, SIGNAL(changed(bool)), SIGNAL(changed(bool))); connect(users, SIGNAL(setMinMaxUID(int,int)), SLOT(slotMinMaxUID(int,int))); connect(this, SIGNAL(addUsers(const QMap<QString,int> &)), users, SLOT(slotAddUsers(const QMap<QString,int> &))); connect(this, SIGNAL(delUsers(const QMap<QString,int> &)), users, SLOT(slotDelUsers(const QMap<QString,int> &))); connect(this, SIGNAL(clearUsers()), users, SLOT(slotClearUsers())); convenience = new KDMConvenienceWidget(this, 0); tab->addTab(convenience, i18n("Con&venience")); connect(convenience, SIGNAL(changed(bool)), SIGNAL(changed(bool))); connect(this, SIGNAL(addUsers(const QMap<QString,int> &)), convenience, SLOT(slotAddUsers(const QMap<QString,int> &))); connect(this, SIGNAL(delUsers(const QMap<QString,int> &)), convenience, SLOT(slotDelUsers(const QMap<QString,int> &))); connect(this, SIGNAL(clearUsers()), convenience, SLOT(slotClearUsers())); load(); if (getuid() != 0 || !config->checkConfigFilesWritable( true )) { appearance->makeReadOnly(); font->makeReadOnly(); background->makeReadOnly(); users->makeReadOnly(); sessions->makeReadOnly(); convenience->makeReadOnly(); } top->addWidget(tab); }
static void do_enter_key (WDialog * h, int f_pos) { WListbox *chl_list; struct passwd *chl_pass; struct group *chl_grp; int fe; gboolean chl_end, is_owner; do { int result; WDialog *chl_dlg; const char *title; int lxx, lyy, b_pos; is_owner = (f_pos == 3); title = is_owner ? _("owner") : _("group"); lxx = (COLS - 74) / 2 + (is_owner ? 35 : 53); lyy = (LINES - 13) / 2; chl_end = FALSE; chl_dlg = dlg_create (TRUE, lyy, lxx, 13, 17, WPOS_KEEP_DEFAULT, TRUE, dialog_colors, chl_callback, NULL, "[Advanced Chown]", title); /* get new listboxes */ chl_list = listbox_new (1, 1, 11, 15, FALSE, NULL); listbox_add_item (chl_list, LISTBOX_APPEND_AT_END, 0, "<Unknown>", NULL, FALSE); if (is_owner) { /* get and put user names in the listbox */ setpwent (); while ((chl_pass = getpwent ()) != NULL) listbox_add_item (chl_list, LISTBOX_APPEND_SORTED, 0, chl_pass->pw_name, NULL, FALSE); endpwent (); fe = listbox_search_text (chl_list, get_owner (sf_stat->st_uid)); } else { /* get and put group names in the listbox */ setgrent (); while ((chl_grp = getgrent ()) != NULL) listbox_add_item (chl_list, LISTBOX_APPEND_SORTED, 0, chl_grp->gr_name, NULL, FALSE); endgrent (); fe = listbox_search_text (chl_list, get_group (sf_stat->st_gid)); } listbox_select_entry (chl_list, fe); b_pos = chl_list->pos; add_widget (chl_dlg, chl_list); result = dlg_run (chl_dlg); if (result != B_CANCEL) { if (b_pos != chl_list->pos) { gboolean ok = FALSE; char *text; listbox_get_current (chl_list, &text, NULL); if (is_owner) { chl_pass = getpwnam (text); if (chl_pass != NULL) { ok = TRUE; sf_stat->st_uid = chl_pass->pw_uid; } } else { chl_grp = getgrnam (text); if (chl_grp != NULL) { sf_stat->st_gid = chl_grp->gr_gid; ok = TRUE; } } if (ok) { ch_flags[f_pos + 6] = '+'; update_ownership (); } dlg_focus (h); if (ok) print_flags (); } if (result == KEY_LEFT) { if (!is_owner) chl_end = TRUE; dlg_one_up (ch_dlg); f_pos--; } else if (result == KEY_RIGHT) { if (is_owner) chl_end = TRUE; dlg_one_down (ch_dlg); f_pos++; } } /* Here we used to redraw the window */ dlg_destroy (chl_dlg); } while (chl_end); }
struct sys_grent * getgrent_list(void) { struct sys_grent *glist; struct sys_grent *gent; struct group *grp; gent = (struct sys_grent *) malloc(sizeof(struct sys_grent)); if (gent == NULL) { DEBUG (0, ("Out of memory in getgrent_list!\n")); return NULL; } memset(gent, '\0', sizeof(struct sys_grent)); glist = gent; setgrent(); grp = getgrent(); if (grp == NULL) { endgrent(); SAFE_FREE(glist); return NULL; } while (grp != NULL) { int i,num; if (grp->gr_name) { if ((gent->gr_name = strdup(grp->gr_name)) == NULL) goto err; } if (grp->gr_passwd) { if ((gent->gr_passwd = strdup(grp->gr_passwd)) == NULL) goto err; } gent->gr_gid = grp->gr_gid; /* number of strings in gr_mem */ for (num = 0; grp->gr_mem[num]; num++) ; /* alloc space for gr_mem string pointers */ if ((gent->gr_mem = (char **) malloc((num+1) * sizeof(char *))) == NULL) goto err; memset(gent->gr_mem, '\0', (num+1) * sizeof(char *)); for (i=0; i < num; i++) { if ((gent->gr_mem[i] = strdup(grp->gr_mem[i])) == NULL) goto err; } gent->gr_mem[num] = NULL; grp = getgrent(); if (grp) { gent->next = (struct sys_grent *) malloc(sizeof(struct sys_grent)); if (gent->next == NULL) goto err; gent = gent->next; memset(gent, '\0', sizeof(struct sys_grent)); } } endgrent(); return glist; err: endgrent(); DEBUG(0, ("Out of memory in getgrent_list!\n")); grent_free(glist); return NULL; }
int main(int argc, char *argv[]) { struct fstab *fs; struct passwd *pw; struct group *gr; struct quotafile *qfu, *qfg; int i, argnum, maxrun, errs, ch; long done = 0; char *name; errs = maxrun = 0; while ((ch = getopt(argc, argv, "ac:guvl:")) != -1) { switch(ch) { case 'a': aflag++; break; case 'c': if (cflag) usage(); cflag = atoi(optarg); break; case 'g': gflag++; break; case 'u': uflag++; break; case 'v': vflag++; break; case 'l': maxrun = atoi(optarg); break; default: usage(); } } argc -= optind; argv += optind; if ((argc == 0 && !aflag) || (argc > 0 && aflag)) usage(); if (cflag && cflag != 32 && cflag != 64) usage(); if (!gflag && !uflag) { gflag++; uflag++; } if (gflag) { setgrent(); while ((gr = getgrent()) != NULL) (void) addid((u_long)gr->gr_gid, GRPQUOTA, gr->gr_name, NULL); endgrent(); } if (uflag) { setpwent(); while ((pw = getpwent()) != NULL) (void) addid((u_long)pw->pw_uid, USRQUOTA, pw->pw_name, NULL); endpwent(); } /* * The maxrun (-l) option is now deprecated. */ if (maxrun > 0) warnx("the -l option is now deprecated"); if (aflag) exit(checkfstab(uflag, gflag)); if (setfsent() == 0) errx(1, "%s: can't open", FSTAB); while ((fs = getfsent()) != NULL) { if (((argnum = oneof(fs->fs_file, argv, argc)) >= 0 || (argnum = oneof(fs->fs_spec, argv, argc)) >= 0) && (name = blockcheck(fs->fs_spec))) { done |= 1 << argnum; qfu = NULL; if (uflag) qfu = quota_open(fs, USRQUOTA, O_CREAT|O_RDWR); qfg = NULL; if (gflag) qfg = quota_open(fs, GRPQUOTA, O_CREAT|O_RDWR); if (qfu == NULL && qfg == NULL) continue; errs += chkquota(name, qfu, qfg); if (qfu) quota_close(qfu); if (qfg) quota_close(qfg); } } endfsent(); for (i = 0; i < argc; i++) if ((done & (1 << i)) == 0) fprintf(stderr, "%s not found in %s\n", argv[i], FSTAB); exit(errs); }
static int #if defined(USE_PAM) || defined(_AIX) isNoPassAllowed( const char *un ) { struct passwd *pw = 0; # ifdef HAVE_GETSPNAM /* (sic!) - not USESHADOW */ struct spwd *spw; # endif #else isNoPassAllowed( const char *un, struct passwd *pw ) { #endif struct group *gr; char **fp; int hg; if (!*un) return 0; if (cursource != PWSRC_MANUAL) return 1; for (hg = 0, fp = td->noPassUsers; *fp; fp++) if (**fp == '@') hg = 1; else if (!strcmp( un, *fp )) return 1; else if (!strcmp( "*", *fp )) { #if defined(USE_PAM) || defined(_AIX) if (!(pw = getpwnam( un ))) return 0; if (pw->pw_passwd[0] == '!' || pw->pw_passwd[0] == '*') continue; # ifdef HAVE_GETSPNAM /* (sic!) - not USESHADOW */ if ((spw = getspnam( un )) && (spw->sp_pwdp[0] == '!' || spw->sp_pwdp[0] == '*')) continue; # endif #endif if (pw->pw_uid) return 1; } #if defined(USE_PAM) || defined(_AIX) if (hg && (pw || (pw = getpwnam( un )))) { #else if (hg) { #endif for (setgrent(); (gr = getgrent()); ) for (fp = td->noPassUsers; *fp; fp++) if (**fp == '@' && !strcmp( gr->gr_name, *fp + 1 )) { if (pw->pw_gid == gr->gr_gid) { endgrent(); return 1; } for (; *gr->gr_mem; gr->gr_mem++) if (!strcmp( un, *gr->gr_mem )) { endgrent(); return 1; } } endgrent(); } return 0; } #if !defined(USE_PAM) && !defined(_AIX) && defined(HAVE_SETUSERCONTEXT) # define LC_RET0 do { login_close(lc); return 0; } while(0) #else # define LC_RET0 return 0 #endif int verify( GConvFunc gconv, int rootok ) { #ifdef USE_PAM const char *psrv; struct pam_data pdata; int pretc, pnopass; char psrvb[64]; #elif defined(_AIX) char *msg, *curret; int i, reenter; #else struct stat st; const char *nolg; char *buf; int fd; # ifdef HAVE_GETUSERSHELL char *s; # endif # if defined(HAVE_STRUCT_PASSWD_PW_EXPIRE) || defined(USESHADOW) int tim, expir, warntime, quietlog; # endif #endif debug( "verify ...\n" ); #ifdef USE_PAM pnopass = FALSE; if (!strcmp( curtype, "classic" )) { if (!gconv( GCONV_USER, 0 )) return 0; if (isNoPassAllowed( curuser )) { gconv( GCONV_PASS_ND, 0 ); if (!*curpass) { pnopass = TRUE; sprintf( psrvb, "%.31s-np", PAMService ); psrv = psrvb; } else psrv = PAMService; } else psrv = PAMService; pdata.usecur = TRUE; } else { sprintf( psrvb, "%.31s-%.31s", PAMService, curtype ); psrv = psrvb; pdata.usecur = FALSE; } pdata.gconv = gconv; if (!doPAMAuth( psrv, &pdata )) return 0; #elif defined(_AIX) if ((td->displayType & d_location) == dForeign) { char *tmpch; strncpy( hostname, td->name, sizeof(hostname) - 1 ); hostname[sizeof(hostname)-1] = '\0'; if ((tmpch = strchr( hostname, ':' ))) *tmpch = '\0'; } else hostname[0] = '\0'; /* tty names should only be 15 characters long */ # if 0 for (i = 0; i < 15 && td->name[i]; i++) { if (td->name[i] == ':' || td->name[i] == '.') tty[i] = '_'; else tty[i] = td->name[i]; } tty[i] = '\0'; # else memcpy( tty, "/dev/xdm/", 9 ); for (i = 0; i < 6 && td->name[i]; i++) { if (td->name[i] == ':' || td->name[i] == '.') tty[9 + i] = '_'; else tty[9 + i] = td->name[i]; } tty[9 + i] = '\0'; # endif if (!strcmp( curtype, "classic" )) { if (!gconv( GCONV_USER, 0 )) return 0; if (isNoPassAllowed( curuser )) { gconv( GCONV_PASS_ND, 0 ); if (!*curpass) { debug( "accepting despite empty password\n" ); goto done; } } else if (!gconv( GCONV_PASS, 0 )) return 0; enduserdb(); msg = NULL; if ((i = authenticate( curuser, curpass, &reenter, &msg ))) { debug( "authenticate() failed: %s\n", msg ); if (msg) free( msg ); loginfailed( curuser, hostname, tty ); if (i == ENOENT || i == ESAD) V_RET_AUTH; else V_RET_FAIL( 0 ); } if (reenter) { logError( "authenticate() requests more data: %s\n", msg ); free( msg ); V_RET_FAIL( 0 ); } } else if (!strcmp( curtype, "generic" )) { if (!gconv( GCONV_USER, 0 )) return 0; for (curret = 0;;) { msg = NULL; if ((i = authenticate( curuser, curret, &reenter, &msg ))) { debug( "authenticate() failed: %s\n", msg ); if (msg) free( msg ); loginfailed( curuser, hostname, tty ); if (i == ENOENT || i == ESAD) V_RET_AUTH; else V_RET_FAIL( 0 ); } if (curret) free( curret ); if (!reenter) break; if (!(curret = gconv( GCONV_HIDDEN, msg ))) return 0; free( msg ); } } else { logError( "Unsupported authentication type %\"s requested\n", curtype ); V_RET_FAIL( 0 ); } if (msg) { displayStr( V_MSG_INFO, msg ); free( msg ); } done: #else if (strcmp( curtype, "classic" )) { logError( "Unsupported authentication type %\"s requested\n", curtype ); V_RET_FAIL( 0 ); } if (!gconv( GCONV_USER, 0 )) return 0; if (!(p = getpwnam( curuser ))) { debug( "getpwnam() failed.\n" ); gconv( GCONV_PASS, 0 ); V_RET_AUTH; } if (p->pw_passwd[0] == '!' || p->pw_passwd[0] == '*') { debug( "account is locked\n" ); gconv( GCONV_PASS, 0 ); V_RET_AUTH; } # ifdef USESHADOW if ((sp = getspnam( curuser ))) { p->pw_passwd = sp->sp_pwdp; if (p->pw_passwd[0] == '!' || p->pw_passwd[0] == '*') { debug( "account is locked\n" ); gconv( GCONV_PASS, 0 ); V_RET_AUTH; } } else debug( "getspnam() failed: %m. Are you root?\n" ); # endif if (!*p->pw_passwd) { if (!td->allowNullPasswd) { debug( "denying user with empty password\n" ); gconv( GCONV_PASS, 0 ); V_RET_AUTH; } goto nplogin; } if (isNoPassAllowed( curuser, p )) { nplogin: gconv( GCONV_PASS_ND, 0 ); if (!*curpass) { debug( "accepting password-less login\n" ); goto done; } } else if (!gconv( GCONV_PASS, 0 )) return 0; # ifdef KERBEROS if (p->pw_uid) { int ret; char realm[REALM_SZ]; if (krb_get_lrealm( realm, 1 )) { logError( "Cannot get KerberosIV realm.\n" ); V_RET_FAIL( 0 ); } sprintf( krbtkfile, "%s.%.*s", TKT_ROOT, MAXPATHLEN - strlen( TKT_ROOT ) - 2, td->name ); krb_set_tkt_string( krbtkfile ); unlink( krbtkfile ); ret = krb_verify_user( curuser, "", realm, curpass, 1, "rcmd" ); if (ret == KSUCCESS) { chown( krbtkfile, p->pw_uid, p->pw_gid ); debug( "KerberosIV verify succeeded\n" ); goto done; } else if (ret != KDC_PR_UNKNOWN && ret != SKDC_CANT) { logError( "KerberosIV verification failure %\"s for %s\n", krb_get_err_text( ret ), curuser ); krbtkfile[0] = '\0'; V_RET_FAIL( 0 ); } debug( "KerberosIV verify failed: %s\n", krb_get_err_text( ret ) ); } krbtkfile[0] = '\0'; # endif /* KERBEROS */ # if defined(ultrix) || defined(__ultrix__) if (authenticate_user( p, curpass, NULL ) < 0) # elif defined(HAVE_PW_ENCRYPT) if (strcmp( pw_encrypt( curpass, p->pw_passwd ), p->pw_passwd )) # elif defined(HAVE_CRYPT) if (strcmp( crypt( curpass, p->pw_passwd ), p->pw_passwd )) # else if (strcmp( curpass, p->pw_passwd )) # endif { debug( "password verify failed\n" ); V_RET_AUTH; } done: #endif /* !defined(USE_PAM) && !defined(_AIX) */ debug( "restrict %s ...\n", curuser ); #if defined(USE_PAM) || defined(_AIX) if (!(p = getpwnam( curuser ))) { logError( "getpwnam(%s) failed.\n", curuser ); V_RET_FAIL( 0 ); } #endif if (!p->pw_uid) { if (!rootok && !td->allowRootLogin) V_RET_FAIL( "Root logins are not allowed" ); return 1; /* don't deny root to log in */ } #ifdef USE_PAM debug( " pam_acct_mgmt() ...\n" ); pretc = pam_acct_mgmt( pamh, 0 ); reInitErrorLog(); debug( " pam_acct_mgmt() returned: %s\n", pam_strerror( pamh, pretc ) ); if (pretc == PAM_NEW_AUTHTOK_REQD) { pdata.usecur = FALSE; pdata.gconv = conv_interact; /* pam will have output a message already, so no prepareErrorGreet() */ if (gconv != conv_interact || pnopass) { pam_end( pamh, PAM_SUCCESS ); pamh = 0; gSendInt( V_CHTOK_AUTH ); /* this cannot auth the wrong user, as only classic auths get here */ while (!doPAMAuth( PAMService, &pdata )) if (pdata.abort) return 0; gSendInt( V_PRE_OK ); } else gSendInt( V_CHTOK ); for (;;) { debug( " pam_chauthtok() ...\n" ); pretc = pam_chauthtok( pamh, PAM_CHANGE_EXPIRED_AUTHTOK ); reInitErrorLog(); debug( " pam_chauthtok() returned: %s\n", pam_strerror( pamh, pretc ) ); if (pdata.abort) { pam_end( pamh, PAM_SUCCESS ); pamh = 0; return 0; } if (pretc == PAM_SUCCESS) break; /* effectively there is only PAM_AUTHTOK_ERR */ gSendInt( V_FAIL ); } if (curpass) free( curpass ); curpass = newpass; newpass = 0; } else if (pretc != PAM_SUCCESS) { pam_end( pamh, pretc ); pamh = 0; V_RET_AUTH; } #elif defined(_AIX) /* USE_PAM */ msg = NULL; if (loginrestrictions( curuser, ((td->displayType & d_location) == dForeign) ? S_RLOGIN : S_LOGIN, tty, &msg ) == -1) { debug( "loginrestrictions() - %s\n", msg ? msg : "error" ); loginfailed( curuser, hostname, tty ); prepareErrorGreet(); if (msg) { displayStr( V_MSG_ERR, msg ); free( msg ); } gSendInt( V_AUTH ); return 0; } if (msg) free( (void *)msg ); #endif /* USE_PAM || _AIX */ #ifndef _AIX # ifdef HAVE_SETUSERCONTEXT # ifdef HAVE_LOGIN_GETCLASS lc = login_getclass( p->pw_class ); # else lc = login_getpwclass( p ); # endif if (!lc) V_RET_FAIL( 0 ); p->pw_shell = login_getcapstr( lc, "shell", p->pw_shell, p->pw_shell ); # endif # ifndef USE_PAM /* restrict_expired */ # if defined(HAVE_STRUCT_PASSWD_PW_EXPIRE) || defined(USESHADOW) # if !defined(HAVE_STRUCT_PASSWD_PW_EXPIRE) || (!defined(HAVE_SETUSERCONTEXT) && defined(USESHADOW)) if (sp) # endif { # define DEFAULT_WARN (2L * 7L) /* Two weeks */ tim = time( NULL ) / 86400L; # ifdef HAVE_SETUSERCONTEXT quietlog = login_getcapbool( lc, "hushlogin", 0 ); warntime = login_getcaptime( lc, "warnexpire", DEFAULT_WARN * 86400L, DEFAULT_WARN * 86400L ) / 86400L; # else quietlog = 0; # ifdef USESHADOW warntime = sp->sp_warn != -1 ? sp->sp_warn : DEFAULT_WARN; # else warntime = DEFAULT_WARN; # endif # endif # ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE if (p->pw_expire) { expir = p->pw_expire / 86400L; # else if (sp->sp_expire != -1) { expir = sp->sp_expire; # endif if (tim > expir) { displayStr( V_MSG_ERR, "Your account has expired;" " please contact your system administrator" ); gSendInt( V_FAIL ); LC_RET0; } else if (tim > (expir - warntime) && !quietlog) { displayMsg( V_MSG_INFO, "Warning: your account will expire in %d day(s)", expir - tim ); } } # ifdef HAVE_STRUCT_PASSWD_PW_EXPIRE if (p->pw_change) { expir = p->pw_change / 86400L; # else if (!sp->sp_lstchg) { displayStr( V_MSG_ERR, "You are required to change your password immediately" " (root enforced)" ); /* XXX todo password change */ gSendInt( V_FAIL ); LC_RET0; } else if (sp->sp_max != -1) { expir = sp->sp_lstchg + sp->sp_max; if (sp->sp_inact != -1 && tim > expir + sp->sp_inact) { displayStr( V_MSG_ERR, "Your account has expired;" " please contact your system administrator" ); gSendInt( V_FAIL ); LC_RET0; } # endif if (tim > expir) { displayStr( V_MSG_ERR, "You are required to change your password immediately" " (password aged)" ); /* XXX todo password change */ gSendInt( V_FAIL ); LC_RET0; } else if (tim > (expir - warntime) && !quietlog) { displayMsg( V_MSG_INFO, "Warning: your password will expire in %d day(s)", expir - tim ); } } } # endif /* HAVE_STRUCT_PASSWD_PW_EXPIRE || USESHADOW */ /* restrict_nologin */ # ifndef _PATH_NOLOGIN # define _PATH_NOLOGIN "/etc/nologin" # endif if (( # ifdef HAVE_SETUSERCONTEXT /* Do we ignore a nologin file? */ !login_getcapbool( lc, "ignorenologin", 0 )) && (!stat( (nolg = login_getcapstr( lc, "nologin", "", NULL )), &st ) || # endif !stat( (nolg = _PATH_NOLOGIN), &st ))) { if (st.st_size && (fd = open( nolg, O_RDONLY )) >= 0) { if ((buf = Malloc( st.st_size + 1 ))) { if (read( fd, buf, st.st_size ) == st.st_size) { close( fd ); buf[st.st_size] = 0; displayStr( V_MSG_ERR, buf ); free( buf ); gSendInt( V_FAIL ); LC_RET0; } free( buf ); } close( fd ); } displayStr( V_MSG_ERR, "Logins are not allowed at the moment.\nTry again later" ); gSendInt( V_FAIL ); LC_RET0; } /* restrict_time */ # if defined(HAVE_SETUSERCONTEXT) && defined(HAVE_AUTH_TIMEOK) if (!auth_timeok( lc, time( NULL ) )) { displayStr( V_MSG_ERR, "You are not allowed to login at the moment" ); gSendInt( V_FAIL ); LC_RET0; } # endif # ifdef HAVE_GETUSERSHELL for (;;) { if (!(s = getusershell())) { debug( "shell not in /etc/shells\n" ); endusershell(); V_RET_FAIL( "Your login shell is not listed in /etc/shells" ); } if (!strcmp( s, p->pw_shell )) { endusershell(); break; } } # endif # endif /* !USE_PAM */ /* restrict_nohome */ # ifdef HAVE_SETUSERCONTEXT if (login_getcapbool( lc, "requirehome", 0 )) { struct stat st; if (!*p->pw_dir || stat( p->pw_dir, &st ) || st.st_uid != p->pw_uid) { displayStr( V_MSG_ERR, "Home folder not available" ); gSendInt( V_FAIL ); LC_RET0; } } # endif #endif /* !_AIX */ return 1; } static const char *envvars[] = { "TZ", /* SYSV and SVR4, but never hurts */ #ifdef _AIX "AUTHSTATE", /* for kerberos */ #endif NULL }; #if defined(USE_PAM) && defined(HAVE_INITGROUPS) static int num_saved_gids; static gid_t *saved_gids; static int saveGids( void ) { num_saved_gids = getgroups( 0, 0 ); if (!(saved_gids = Malloc( sizeof(gid_t) * num_saved_gids ))) return 0; if (getgroups( num_saved_gids, saved_gids ) < 0) { logError( "saving groups failed: %m\n" ); return 0; } return 1; } static int restoreGids( void ) { if (setgroups( num_saved_gids, saved_gids ) < 0) { logError( "restoring groups failed: %m\n" ); return 0; } if (setgid( p->pw_gid ) < 0) { logError( "restoring gid failed: %m\n" ); return 0; } return 1; } #endif /* USE_PAM && HAVE_INITGROUPS */ static int resetGids( void ) { #ifdef HAVE_INITGROUPS if (setgroups( 0, &p->pw_gid /* anything */ ) < 0) { logError( "restoring groups failed: %m\n" ); return 0; } #endif if (setgid( 0 ) < 0) { logError( "restoring gid failed: %m\n" ); return 0; } return 1; } static int setGid( const char *name, int gid ) { if (setgid( gid ) < 0) { logError( "setgid(%d) (user %s) failed: %m\n", gid, name ); return 0; } #ifdef HAVE_INITGROUPS if (initgroups( name, gid ) < 0) { logError( "initgroups for %s failed: %m\n", name ); setgid( 0 ); return 0; } #endif /* QNX4 doesn't support multi-groups, no initgroups() */ return 1; } static int setUid( const char *name, int uid ) { if (setuid( uid ) < 0) { logError( "setuid(%d) (user %s) failed: %m\n", uid, name ); return 0; } return 1; } static int setUser( const char *name, int uid, int gid ) { if (setGid( name, gid )) { if (setUid( name, uid )) return 1; resetGids(); } return 0; } #if defined(SECURE_RPC) || defined(K5AUTH) static void nukeAuth( int len, const char *name ) { int i; for (i = 0; i < td->authNum; i++) if (td->authorizations[i]->name_length == len && !memcmp( td->authorizations[i]->name, name, len )) { memcpy( &td->authorizations[i], &td->authorizations[i+1], sizeof(td->authorizations[i]) * (--td->authNum - i) ); break; } } #endif static void mergeSessionArgs( int cansave ) { char *mfname; const char *fname; int i, needsave; mfname = 0; fname = ".dmrc"; if ((!curdmrc || newdmrc) && *dmrcDir) if (strApp( &mfname, dmrcDir, "/", curuser, fname, (char *)0 )) fname = mfname; needsave = 0; if (!curdmrc) { curdmrc = iniLoad( fname ); if (!curdmrc) { strDup( &curdmrc, "[Desktop]\nSession=default\n" ); needsave = 1; } } if (newdmrc) { curdmrc = iniMerge( curdmrc, newdmrc ); needsave = 1; } if (needsave && cansave) if (!iniSave( curdmrc, fname ) && errno == ENOENT && mfname) { for (i = 0; mfname[i]; i++) if (mfname[i] == '/') { mfname[i] = 0; mkdir( mfname, 0755 ); mfname[i] = '/'; } iniSave( curdmrc, mfname ); } if (mfname) free( mfname ); } static int createClientLog( const char *log ) { char randstr[32], *randstrp = 0, *lname; int lfd; for (;;) { struct expando macros[] = { { 'd', 0, td->name }, { 'u', 0, curuser }, { 'r', 0, randstrp }, { 0, 0, 0 } }; if (!(lname = expandMacros( log, macros ))) exit( 1 ); unlink( lname ); if ((lfd = open( lname, O_WRONLY|O_CREAT|O_EXCL, 0600 )) >= 0) { dup2( lfd, 1 ); dup2( lfd, 2 ); close( lfd ); free( lname ); return TRUE; } if (errno != EEXIST || !macros[2].uses) { free( lname ); return FALSE; } logInfo( "Session log file %s not usable, trying another one.\n", lname ); free( lname ); sprintf( randstr, "%d", secureRandom() ); randstrp = randstr; } }