/** Write the access.cnf file. * Writes out the access.cnf file from the linked list */ void write_access_file(void) { FILE *fp; char tmpf[BUFFER_LEN]; struct access *ap; acsflag *c; snprintf(tmpf, BUFFER_LEN, "%s.tmp", ACCESS_FILE); /* Be sure we have a file descriptor */ release_fd(); fp = fopen(tmpf, FOPEN_WRITE); if (!fp) { do_log(LT_ERR, GOD, GOD, "Unable to open %s.", tmpf); } else { for (ap = access_top; ap; ap = ap->next) { if (strcmp(ap->host, "@sitelock") == 0) { fprintf(fp, "@sitelock\n"); continue; } fprintf(fp, "%s %d ", ap->host, ap->who); switch (ap->can) { case ACS_SITELOCK: break; case ACS_DEFAULT: fprintf(fp, "DEFAULT "); break; default: for (c = acslist; c->name; c++) if (ap->can & c->flag) fprintf(fp, "%s ", c->name); break; } switch (ap->cant) { case ACS_DEFAULT: fprintf(fp, "NONE "); break; default: for (c = acslist; c->name; c++) if (c->toggle && (ap->cant & c->flag)) fprintf(fp, "!%s ", c->name); break; } if (ap->comment) fprintf(fp, "# %s\n", ap->comment); else fputc('\n', fp); } fclose(fp); rename_file(tmpf, ACCESS_FILE); } reserve_fd(); return; }
/** Read the access.cnf file. * Initialize the access rules linked list and read in the access.cnf file. * \return true if successful, false if not */ bool read_access_file(void) { FILE *fp; char buf[BUFFER_LEN]; char *p; uint32_t can, cant; int retval; dbref who; char *comment; const char *errptr = NULL; if (access_top) { /* We're reloading the file, so we've got to delete any current * entries */ free_access_list(); } access_top = NULL; /* Be sure we have a file descriptor */ release_fd(); fp = fopen(ACCESS_FILE, FOPEN_READ); if (!fp) { do_rawlog(LT_ERR, "Access file %s not found.", ACCESS_FILE); retval = 0; } else { do_rawlog(LT_ERR, "Reading %s", ACCESS_FILE); while (fgets(buf, BUFFER_LEN, fp)) { /* Strip end of line if it's \r\n or \n */ if ((p = strchr(buf, '\r'))) *p = '\0'; else if ((p = strchr(buf, '\n'))) *p = '\0'; /* Find beginning of line; ignore blank lines */ p = buf; if (*p && isspace((unsigned char) *p)) p++; if (*p && *p != '#') { can = cant = 0; comment = NULL; /* Is this the @sitelock entry? */ if (!strncasecmp(p, "@sitelock", 9)) { if (!add_access_node("@sitelock", AMBIGUOUS, ACS_SITELOCK, 0, "", &errptr)) do_log(LT_ERR, GOD, GOD, "Failed to add sitelock node: %s", errptr); } else { if ((comment = strchr(p, '#'))) { *comment++ = '\0'; while (*comment && isspace((unsigned char) *comment)) comment++; } /* Move past the host name */ while (*p && !isspace((unsigned char) *p)) p++; if (*p) *p++ = '\0'; if (!parse_access_options(p, &who, &can, &cant, NOTHING)) /* Nothing listed, so assume we can't do anything! */ cant = ACS_DEFAULT; if (!add_access_node(buf, who, can, cant, comment, &errptr)) do_log(LT_ERR, GOD, GOD, "Failed to add access node: %s", errptr); } } } retval = 1; fclose(fp); } reserve_fd(); return retval; }
/** Attempt to register a new player at the connect screen. * If registration is allowed, a new player object is created with * a random password which is emailed to the registering player. * \param name name of player to register. * \param email email address to send registration details. * \param host host from which registration is being attempted. * \param ip ip address from which registration is being attempted. * \return dbref of created player or NOTHING if creation failed. */ dbref email_register_player(DESC *d, const char *name, const char *email, const char *host, const char *ip) { char *p; char passwd[20]; static char elems[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; int i, len; bool resend = 0; dbref player = NOTHING; FILE *fp; size_t NELEMS = sizeof(elems) - 1; char sbuff[260]; if (!check_fails(ip)) { return NOTHING; } if (strlen(options.sendmail_prog) == 0) return NOTHING; if (!ok_player_name(name, NOTHING, NOTHING)) { /* Check for re-registration request */ player = lookup_player(name); if (GoodObject(player)) { ATTR *a; a = atr_get(player, "LASTLOGOUT"); if (!a) { a = atr_get(player, "REGISTERED_EMAIL"); if (a && !strcasecmp(atr_value(a), email)) resend = 1; } } if (!resend) { do_log(LT_CONN, 0, 0, "Failed registration (bad name) from %s", host); queue_event(SYSEVENT, "SOCKET`CREATEFAIL", "%d,%s,%d,%s,%s", d->descriptor, ip, mark_failed(ip), "register: bad name", name); return NOTHING; } } if (!resend) { /* Make sure that the email address is kind of valid. A valid * address must contain a @. Let the mailer sort it out beyond * that. Also, to prevent someone from using the MUSH to mailbomb * another site, let's make sure that the site to which the user * wants the email sent is also allowed to use the register * command. If there's an @, we check whatever's after the last @ * (since @foo.bar:user@host is a valid email). */ if ((p = strrchr(email, '@'))) { p++; if (!Site_Can_Register(p)) { if (!Deny_Silent_Site(p, AMBIGUOUS)) { do_log(LT_CONN, 0, 0, "Failed registration (bad site in email: %s) from %s", email, host); queue_event(SYSEVENT, "SOCKET`CREATEFAIL", "%d,%s,%d,%s,%s", d->descriptor, ip, mark_failed(ip), "register: bad site in email", name); } return NOTHING; } } else { if (!Deny_Silent_Site(host, AMBIGUOUS)) { do_log(LT_CONN, 0, 0, "Failed registration (bad email: %s) from %s", email, host); queue_event(SYSEVENT, "SOCKET`CREATEFAIL", "%d,%s,%d,%s,%s", d->descriptor, ip, mark_failed(ip), "register: sitelocked host", name); } return NOTHING; } if (DBTOP_MAX && (db_top >= DBTOP_MAX + 1) && (first_free == NOTHING)) { /* Oops, out of db space! */ do_log(LT_CONN, 0, 0, "Failed registration (no db space) from %s", host); queue_event(SYSEVENT, "SOCKET`CREATEFAIL", "%d,%s,%d,%s,%s", d->descriptor, ip, count_failed(ip), "register: no db space left to create!", name); return NOTHING; } } /* Come up with a random password of length 7-12 chars */ len = get_random_u32(7, 12); for (i = 0; i < len; i++) passwd[i] = elems[get_random_u32(0, NELEMS - 1)]; passwd[len] = '\0'; /* If we've made it here, we can send the email and create the * character. Email first, since that's more likely to go bad. * Some security precautions we'll take: * 1) We'll use sendmail -t, so we don't pass user-given values to a shell. * 2) We'll cross our fingers and hope nobody uses this to spam. */ release_fd(); snprintf(sbuff, sizeof sbuff, "%s -t", options.sendmail_prog); if ((fp = popen(sbuff, "w")) == NULL) { do_log(LT_CONN, 0, 0, "Failed registration of %s by %s: unable to open sendmail", name, email); queue_event(SYSEVENT, "SOCKET`CREATEFAIL", "%d,%s,%d,%s,%s,%d", d->descriptor, ip, count_failed(ip), "register: Unable to open sendmail!", name, 1); reserve_fd(); return NOTHING; } fprintf(fp, "Subject: "); fprintf(fp, T("[%s] Registration of %s\n"), MUDNAME, name); fprintf(fp, "To: %s\n", email); fprintf(fp, "Precedence: junk\n"); fprintf(fp, "\n"); fprintf(fp, T("This is an automated message.\n")); fprintf(fp, "\n"); fprintf(fp, T("Your requested player, %s, has been created.\n"), name); fprintf(fp, T("The password is %s\n"), passwd); fprintf(fp, "\n"); fprintf(fp, T("To access this character, connect to %s and type:\n"), MUDNAME); fprintf(fp, "\tconnect \"%s\" %s\n", name, passwd); fprintf(fp, "\n"); i = pclose(fp); reserve_fd(); if (i != 0) { /* Mailer exited with an error code. Log it. */ do_rawlog( LT_CONN, "When attempting to email a password to a newly registered player,\n" "\tthe mailer exited with error code %d.\n" "\t(Check /usr/include/sysexits.h if present for the meaning.)", i); queue_event(SYSEVENT, "SOCKET`CREATEFAIL", "%d,%s,%d,%s,%s,%d", d->descriptor, ip, count_failed(ip), "register: Unable to send email", name, i); return NOTHING; } else if (resend) { /* Reset the password */ (void) atr_add(player, pword_attr, password_hash(passwd, NULL), GOD, 0); return player; } else { /* Ok, all's well, make a player */ player = make_player(name, passwd, host, ip); queue_event(SYSEVENT, "PLAYER`CREATE", "%s,%s,%s,%d,%s", unparse_objid(player), name, "register", d->descriptor, email); (void) atr_add(player, "REGISTERED_EMAIL", email, GOD, 0); return player; } }