/* YOUR FILE-HEADER COMMENT HERE */ /* * This file uses kernel-doc style comments, which is similar to * Javadoc and Doxygen-style comments. See * ~/linux/Documentation/kernel-doc-nano-HOWTO.txt for details. */ /* * Getting compilation warnings? The Linux kernel is written against * C89, which means: * - No // comments, and * - All variables must be declared at the top of functions. * Read ~/linux/Documentation/CodingStyle to ensure your project * compiles without warnings. */ #define pr_fmt(fmt) "pwkeeper: " fmt #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "xt_cs421net.h" #define MASTERPW_LEN 32 #define ACCOUNTNAME_LEN 16 #define ACCOUNTPW_LEN 16 /** * pwkeeper_master_write() - callback invoked when a process writes to * /dev/pwkeeper_master * @filp: process's file object that is writing to this device (ignored) * @ubuf: source buffer from user * @count: number of bytes in @ubuf * @ppos: file offset (in/out parameter) * * If *@ppos does not point to zero, do nothing and return -EINVAL. * * Copy the contents of @ubuf to the master password for the user, the * lesser of @count and MASTERPW_LEN. Then increment the value pointed * to by @ppos by the number of bytes copied. * * When replacing an existing master password, recalculate all account * passwords. * * Caution: @ubuf is not a string; it is not null-terminated. * * Return: number of bytes copied from @ubuf, or negative on error */ static ssize_t pwkeeper_master_write(struct file *filp, const char __user * ubuf, size_t count, loff_t * ppos) { /* Part 2: YOUR CODE HERE */ return -EPERM; } /** * pwkeeper_account_read() - callback invoked when a process reads * from /dev/pwkeeper_account * @filp: process's file object that is reading from this device (ignored) * @ubuf: destination to store account password * @count: number of bytes in @ubuf * @ppos: file offset (in/out parameter) * * Write to @ubuf the password generated for the most recently written * account name for the current UID, offset by @ppos. Copy the lesser * of @count and (ACCOUNTPW_LEN - *@ppos). Then increment the value * pointed to by @ppos by the number of bytes written. If @ppos is * greater than or equal to ACCOUNTPW_LEN, then write * nothing. * * If no account name was set (via previous successful invocation of * pwkeeper_account_write()), do nothing and return -ENOKEY. * * Return: number of bytes written to @ubuf, 0 on end of file, or * negative on error */ static ssize_t pwkeeper_account_read(struct file *filp, char __user * ubuf, size_t count, loff_t * ppos) { /* Part 3: YOUR CODE HERE */ return -EPERM; } /** * pwkeeper_account_write() - callback invoked when a process writes * to /dev/pwkeeper_account * @filp: process's file object that is writing to this device (ignored) * @ubuf: source buffer from user * @count: number of bytes in @ubuf * @ppos: file offset (in/out parameter) * * If *@ppos does not point to zero, do nothing and return -EINVAL. * * If the current user has not set a master password, do nothing and * return -ENOKEY. * * Otherwise check if @ubuf is already in the accounts list associated * with the current user. If it is already there, do nothing and * return @count. * * Otherwise, create a new node in the accounts list associated with * the current user. Copy the contents of @ubuf to that node, the * lesser of @count and ACCOUNTNAME_LEN. Increment the value pointed * to by @ppos by the number of bytes copied. Finally, perform the key * derivation function as specified in the project description, to * determine the account's password. * * Caution: @ubuf is not a string; it is not null-terminated. * * Return: @count, or negative on error */ static ssize_t pwkeeper_account_write(struct file *filp, const char __user * ubuf, size_t count, loff_t * ppos) { /* Part 3: YOUR CODE HERE */ return -EPERM; } static const struct file_operations pwkeeper_master_fops = { .write = pwkeeper_master_write, }; static struct miscdevice pwkeeper_master_dev = { .minor = MISC_DYNAMIC_MINOR, .name = "pwkeeper_master", .fops = &pwkeeper_master_fops, .mode = 0666 }; static const struct file_operations pwkeeper_account_fops = { .read = pwkeeper_account_read, .write = pwkeeper_account_write, }; static struct miscdevice pwkeeper_account_dev = { .minor = MISC_DYNAMIC_MINOR, .name = "pwkeeper_account", .fops = &pwkeeper_account_fops, .mode = 0666 }; /** * cs421net_top() - top-half of CS421Net ISR * @irq: IRQ that was invoked (ignored) * @cookie: Pointer to data that was passed into * request_threaded_irq() (ignored) * * If @irq is CS421NET_IRQ, then wake up the bottom-half. Otherwise, * return IRQ_NONE. */ static irqreturn_t cs421net_top(int irq, void *cookie) { /* Part 4: YOUR CODE HERE */ return 0; } /** * cs421net_bottom() - bottom-half to CS421Net ISR * @irq: IRQ that was invoked (ignore) * @cookie: Pointer that was passed into request_threaded_irq() * (ignored) * * Fetch the incoming packet, via cs421net_get_data(). Check if the * given account name and password are in the accounts list (for any * UID). If the values match, increment the number of successful login * attempts. If the account name and/or password are incorrect, * increment the number of failed login attempts. If the incoming data * are malformed, increment the number of invalid attempts. * * Remember to add appropriate spin lock calls in this function. * * Caution: The incoming payload is not a string; it is not null-terminated. * You can NOT use strcpy() or strlen() on it. * * Return: always IRQ_HANDLED */ static irqreturn_t cs421net_bottom(int irq, void *cookie) { /* Part 4: YOUR CODE HERE */ return IRQ_HANDLED; } /** * pwkeeper_login_show() - callback invoked when a process reads from * /sys/devices/platform/pwkeeper/logins * * @dev: device driver data for sysfs entry (ignored) * @attr: sysfs entry context (ignored) * @buf: destination to store login statistics * * Write to @buf, up to PAGE_SIZE characters, a human-readable message * that describes how many login attempts were successful and how many * failed. Note that @buf is a normal character buffer, not a __user * buffer. Use scnprintf() in this function. * * @return Number of bytes written to @buf, or negative on error. */ static ssize_t pwkeeper_logins_show(struct device *dev, struct device_attribute *attr, char *buf) { /* Part 4: YOUR CODE HERE */ return -EPERM; } static DEVICE_ATTR(logins, S_IRUGO, pwkeeper_logins_show, NULL); /** * pwkeeper_probe() - callback invoked when this driver is probed * @pdev platform device driver data (ignored) * * Return: 0 on successful probing, negative on error */ static int pwkeeper_probe(struct platform_device *pdev) { int retval; retval = misc_register(&pwkeeper_master_dev); if (retval) { pr_err("Could not register master device\n"); goto err; } retval = misc_register(&pwkeeper_account_dev); if (retval) { pr_err("Could not register account device\n"); goto err_deregister_master; } retval = device_create_file(&pdev->dev, &dev_attr_logins); if (retval) { pr_err("Could not create sysfs entry\n"); goto err_deregister_account; } /* * In part 4, register the ISR and enable network * integration. Make sure you clean up upon error. */ /* YOUR CODE HERE */ pr_info("Probe successful\n"); return 0; err_remove_sysfs: device_remove_file(&pdev->dev, &dev_attr_logins); err_deregister_account: misc_deregister(&pwkeeper_account_dev); err_deregister_master: misc_deregister(&pwkeeper_master_dev); err: pr_err("Probe failed, error %d\n", retval); return retval; } /** * pwkeeper_remove() - callback when this driver is removed * @pdev platform device driver data (ignored) * * Return: Always 0 */ static int pwkeeper_remove(struct platform_device *pdev) { pr_info("Removing\n"); /* * In part 4, disable network integration and remove the ISR. */ /* YOUR CODE HERE */ /* * In part 3, free all memory associated with accounts list. */ /* YOUR CODE HERE */ /* * In part 2, free all memory associated with master password * list. */ /* YOUR CODE HERE */ device_remove_file(&pdev->dev, &dev_attr_logins); misc_deregister(&pwkeeper_account_dev); misc_deregister(&pwkeeper_master_dev); return 0; } static struct platform_driver cs421_driver = { .driver = { .name = "pwkeeper", }, .probe = pwkeeper_probe, .remove = pwkeeper_remove, }; static struct platform_device *pdev; /** * cs421_init() - create the platform driver * This is needed so that the device gains a sysfs group. * * You do not need to modify this function. */ static int __init cs421_init(void) { pdev = platform_device_register_simple("pwkeeper", -1, NULL, 0); if (IS_ERR(pdev)) return PTR_ERR(pdev); return platform_driver_register(&cs421_driver); } /** * cs421_exit() - remove the platform driver * Unregister the driver from the platform bus. * * You do not need to modify this function. */ static void __exit cs421_exit(void) { platform_driver_unregister(&cs421_driver); platform_device_unregister(pdev); } module_init(cs421_init); module_exit(cs421_exit); MODULE_DESCRIPTION("CS421 Password Keeper - project 2"); MODULE_LICENSE("GPL");