/*
 * DF-0907 control: same harness as trigger.c but with a SHORT username
 * (10 chars), which does NOT trigger the pe-pc-2 underflow. Used to prove
 * that the kernel panic observed with trigger.c (80-char username) is caused
 * by the line-170/173 overflow, not by the no-server mount attempt.
 *
 * Build:  cc -o control control.c
 */
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <vfs/smbfs/smbfs.h>
#include <netproto/smb/smb.h>
#include <netproto/smb/smb_dev.h>
#include <netproto/smb/smb_conn.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>

int main(void)
{
    int fd, rv;
    struct sockaddr_in sin;
    struct smbioc_lookup iol;
    struct smbfs_args mdata;
    char mountpoint[] = "/mnt/df0907_ctrl";

    mkdir(mountpoint, 0755);
    fd = open("/dev/nsmb", O_RDWR);
    if (fd < 0) err(1, "open /dev/nsmb");

    memset(&sin, 0, sizeof(sin));
    sin.sin_len = sizeof(sin);
    sin.sin_family = AF_INET;
    sin.sin_port = htons(139);
    sin.sin_addr.s_addr = inet_addr("127.0.0.1");

    memset(&iol, 0, sizeof(iol));
    iol.ioc_level = SMBL_SHARE;
    iol.ioc_flags = SMBLK_CREATE;
    iol.ioc_ssn.ioc_opt = SMBVOPT_PRIVATE;
    iol.ioc_ssn.ioc_server = (struct sockaddr *)&sin;
    iol.ioc_ssn.ioc_svlen = sizeof(sin);
    iol.ioc_ssn.ioc_local = (struct sockaddr *)&sin;
    iol.ioc_ssn.ioc_lolen = sizeof(sin);
    iol.ioc_ssn.ioc_timeout = 5;
    iol.ioc_ssn.ioc_retrycount = 1;
    strlcpy(iol.ioc_ssn.ioc_srvname, "X", sizeof(iol.ioc_ssn.ioc_srvname));
    strlcpy(iol.ioc_ssn.ioc_localcs, "ASCII", sizeof(iol.ioc_ssn.ioc_localcs));
    strlcpy(iol.ioc_ssn.ioc_servercs, "ASCII", sizeof(iol.ioc_ssn.ioc_servercs));
    strlcpy(iol.ioc_ssn.ioc_user, "SHORTUSER", sizeof(iol.ioc_ssn.ioc_user)); /* 9 chars */
    iol.ioc_ssn.ioc_owner = 0;
    iol.ioc_ssn.ioc_group = 0;
    iol.ioc_ssn.ioc_mode = SMBM_EXEC;
    iol.ioc_ssn.ioc_rights = SMBM_EXEC;
    strlcpy(iol.ioc_sh.ioc_share, "SHARE", sizeof(iol.ioc_sh.ioc_share));
    iol.ioc_sh.ioc_owner = 0;
    iol.ioc_sh.ioc_group = 0;
    iol.ioc_sh.ioc_mode = SMBM_EXEC;
    iol.ioc_sh.ioc_rights = SMBM_EXEC;

    printf("[*] control: username='SHORTUSER' (9 chars, < 76 -> NO overflow)\n");
    rv = ioctl(fd, SMBIOC_LOOKUP, &iol);
    if (rv != 0) err(2, "SMBIOC_LOOKUP");
    printf("[*] SMBIOC_LOOKUP ok\n");

    memset(&mdata, 0, sizeof(mdata));
    mdata.version = SMBFS_VERSION;
    mdata.dev = fd;
    strlcpy(mdata.mount_point, mountpoint, sizeof(mdata.mount_point));
    mdata.uid = 0; mdata.gid = 0;
    mdata.file_mode = 0644; mdata.dir_mode = 0755;

    printf("[*] issuing mount(SMBFS) with short username (control)\n");
    rv = mount(SMBFS_VFSNAME, mdata.mount_point, 0, &mdata);
    printf("[!] mount returned rv=%d errno=%d (%s)\n", rv, errno, strerror(errno));
    close(fd);
    return (rv == 0) ? 0 : 1;
}
