Skip to content

Instantly share code, notes, and snippets.

@shimarin
Created June 3, 2010 10:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shimarin/423724 to your computer and use it in GitHub Desktop.
Save shimarin/423724 to your computer and use it in GitHub Desktop.
// smbauth.cpp
// g++ smbauth.cpp -DPRIVATE_DIR=\"`testparm -s --parameter-name="private dir"`\" -lssl -lext2fs -o smbauth
// chmod 711 smbauth
// chmod u+s smbauth
// mv smbauth /usr/sbin/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdint.h>
#include <openssl/md4.h>
#include <iconv.h>
#include <ext2fs/tdb.h>
#define STATUS_OK 0 /* Valid Login */
#define STATUS_UNKNOWN 1 /* Login doesn't exist or password incorrect */
#define STATUS_INVALID 2 /* Password was incorrect */
#define STATUS_BLOCKED 3 /* UID is below minimum allowed to use this */
#define STATUS_EXPIRED 4 /* Login ID has passed it's expiration date */
#define STATUS_PW_EXPIRED 5 /* Password has expired and must be changed */
#define STATUS_NOLOGIN 6 /* Logins have been turned off */
#define STATUS_MANYFAILS 7 /* Bad login limit exceeded */
#define STATUS_INT_USER 50 /* pwauth was run by wrong uid */
#define STATUS_INT_ARGS 51 /* login/password not passed in correctly */
#define STATUS_INT_ERR 52 /* Miscellaneous internal errors */
#define STATUS_INT_NOROOT 53 /* pwauth cannot read password database */
#define IVAL(buf,pos) (*(const uint32_t *)((const char *)(buf) + (pos)))
#ifndef PRIVATE_DIR
#define PRIVATE_DIR "/var/lib/samba/private"
#endif
#ifndef BFSZ
# define BFSZ 1024
#endif
uint32_t get_dword(unsigned char*& buf, size_t &len_left)
{
if (len_left < 4) {
throw len_left;
}
uint32_t ret = IVAL(buf, 0);
buf += 4;
len_left -= 4;
return ret;
}
void skip_string(unsigned char*& buf, size_t &len_left)
{
uint32_t len = get_dword(buf, len_left);
if (len_left < len) {
throw len;
}
buf += len;
len_left -= len;
}
int main()
{
// stdinからユーザー名とパスワードを1行ずつでもらう
char login[BFSZ+1], passwd[BFSZ+1];
if (fgets(login, BFSZ, stdin) == NULL ||
fgets(passwd, BFSZ, stdin) == NULL)
return STATUS_INT_ARGS;
char *c;
if ((c= strchr(login,'\n')) != NULL) *c= '\0';
if ((c= strchr(passwd,'\n')) != NULL) *c= '\0';
// パスワードをまずはUCS-2LEに変換する
char* utf8_text = new char[strlen(passwd) + 1];
strcpy(utf8_text, passwd);
size_t utf8_len = strlen(utf8_text);
size_t ucs2buf_len = utf8_len * 2;
char* ucs2_text = new char[ucs2buf_len];
char* inbuf = utf8_text;
char* outbuf = ucs2_text;
size_t inbytesleft = strlen(utf8_text);
size_t outbytesleft = ucs2buf_len;
iconv_t ic = iconv_open("UCS-2LE", "UTF-8");
size_t result = iconv(ic, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
iconv_close(ic);
delete [] utf8_text;
if (result < 0) {
delete [] ucs2_text;
return STATUS_INT_ERR;
}
// UCS-2LEに変換されたパスワードのMD4ハッシュを取る
unsigned char md4[MD4_DIGEST_LENGTH];
MD4((unsigned char*)ucs2_text, ucs2buf_len - outbytesleft, md4);
delete [] ucs2_text; // UCS-2LEのパスワードはもういらないので削除
TDB_CONTEXT * tdb = tdb_open(PRIVATE_DIR"/passdb.tdb", 0, 0, O_RDONLY, 0666);
if (tdb == NULL) {
return STATUS_INT_NOROOT;
}
// sambaのパスワードデータベースからパスワードを読み込む
// データベースではユーザー名は常に小文字で扱う
for (char* pt = login; *pt; pt++) { *pt = tolower(*pt); }
char* key_string = new char[strlen(login) + 6];
sprintf(key_string, "USER_%s", login);
TDB_DATA key;
key.dptr = (unsigned char*)key_string;
key.dsize = strlen(login) + 6;
TDB_DATA data = tdb_fetch(tdb, key);
delete [] key_string;
if (data.dptr == NULL) {
return STATUS_UNKNOWN;
}
size_t left_len = data.dsize;
// dddddddBBBBBBBBBBBBddBB←これ
unsigned char* buf = data.dptr;
try {
for (int i = 0; i < 7; i++) { get_dword(buf, left_len); } // ddddddd
for (int i = 0; i < 12; i++) { skip_string(buf, left_len); }
get_dword(buf, left_len); //d
get_dword(buf, left_len); //d
skip_string(buf, left_len); // B
if (left_len < 4) throw (size_t)4;
uint32_t len = IVAL(buf, 0);
if (left_len < len) throw (size_t)len;
unsigned char* password = new unsigned char[len];
memcpy(password, buf + 4, len);
int result = memcmp(md4, password, MD4_DIGEST_LENGTH);
delete [] password;
if (result != 0) return STATUS_INVALID;
}
catch (size_t len_needed) {
fprintf(stderr, "Buffer length is shorter than needed\n");
tdb_close(tdb);
return -1;
}
tdb_close(tdb);
return STATUS_OK;
}
// unixgroup.cpp
// g++ unixgroup.cpp -o unixgroup
// mv unixgroup /usr/sbin/
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <grp.h>
#include <pwd.h>
bool check_group(const char* user, const char* group)
{
struct passwd* p = getpwnam(user);
struct group* g = getgrnam(group);
if (g->gr_gid == p->pw_gid) return true;
for (int i = 0; g->gr_mem[i] != NULL; i++) {
if (strcmp(g->gr_mem[i], user) == 0) return true;
}
return false;
}
int main()
{
char user[100], groups[100], *group, *p;
if (fgets(user, sizeof(user), stdin) == NULL) return 2;
if ((p= strchr(user, '\n')) == NULL) return 4;
*p= '\0';
if (fgets(groups, sizeof(groups), stdin) == NULL) return 3;
if ((p= strchr(groups, '\n')) == NULL) return 5;
*p= '\0';
group= strtok(groups, " ");
while (group != NULL) {
if (check_group(user, group))
return 0; /* User is in group */
group= strtok(NULL, " ");
}
return 1; /* User is not in any group */
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment